michaelboyles / redcr

Compile-time alternative to Immer
MIT License
6 stars 0 forks source link

[FEATURE] Support loops #9

Open michaelboyles opened 2 years ago

michaelboyles commented 2 years ago

Currently, using a loop in a Redcr reducer can end up mutably editing the state. For example

interface StringState {
    str: String
}
const reducer = redcr((state: StringState) => {
    for (let i = 0; i < 3; i++) {
        state.str += 'A';
    }
});

Will produce

const reducer = (state) => {
    for (let i = 0; i < 3; i++) {
        state.str += 'A';
    }
    return state;
};

It should probably work similar to how if-statements are handled, and continuously reassign the state

const reducer = (state) => {
    for (let i = 0; i < 3; i++) {
        state = {
            ...state,
            str: state.str + 'A'
        }
    }
    return state;
};

Could explore loop unrolling too if the number of iterations is a compile-time constant.

How often is a loop actually useful in a reducer though?

michaelboyles commented 2 years ago

For-loops are now supported. While-loops will require more thought. This code

interface StringState {
    str: string
}
const reducer = redcr((state: StringState) => {
    let i = 1;
    while (i <= 3) {
        state.str += 'A';
        i++;
    }
});

Produces this:

const reducer = (state) => {
    while (1 <= 3) {
        state.str += 'A';
        1++;
    }
    return state;
};

It's caused by unsophisticated local variable removal which incorrectly inlines the counter. Local variables are inlined to support destructuring the state.