How to simplify this code?

I have the following type:

mutable struct JSButtonState
    btn1::Observable{Bool}
    btn2::Observable{Bool}
    btn3::Observable{Bool}
    btn4::Observable{Bool}
    btn5::Observable{Bool}
    btn6::Observable{Bool}
    btn7::Observable{Bool}
    btn8::Observable{Bool}
    btn9::Observable{Bool}
    btn10::Observable{Bool}
    btn11::Observable{Bool}
    btn12::Observable{Bool}
end

And use the following code to set the Observables from the array buttons, which is an array of UInt8 values that are zero or one:

            if ! isnothing(jsbuttons)
                buttons = GLFW.GetJoystickButtons(js.device)
                if js.button_count >= 1  
                    if jsbuttons.btn1[] != (buttons[1]  != 0)
                        jsbuttons.btn1[] = (buttons[1]  != 0)
                    end
                end
                if js.button_count >= 2  
                    if jsbuttons.btn2[] != (buttons[2]  != 0)
                        jsbuttons.btn2[] = (buttons[2]  != 0)
                    end
                end
                if js.button_count >= 3  
                    if jsbuttons.btn3[] != (buttons[3]  != 0)
                        jsbuttons.btn3[] = (buttons[3]  != 0)
                    end
                end
                if js.button_count >= 4  
                    if jsbuttons.btn4[] != (buttons[4]  != 0)
                        jsbuttons.btn4[] = (buttons[4]  != 0)
                    end
                end
                ... # there are 12 buttons or more 
           end

This are lots of lines of code…

Any idea how to simplify the code without changing the type JSButtonState ?

Would be simpler and extensible to put them in a vector.

Macro to generate the if blocks?

3 Likes

How about this:

for (i, b) in Iterators.take(enumerate(buttons), fieldcount(JSButtonState))
    field = Symbol("btn$(i)")
    obs = getfield(jsbuttons, field)
    new = (b != 0)
    if obs.val != new
        obs[] = new
    end
end

Also, for this code, there is no need for JSButtons to be a mutable struct, you are not changing out the Observable just modifying its stored value. Inner Mutability does not require a mutable struct.

3 Likes

@contradict I will try your suggestion! Thanks a lot! :smiley:

Could you please explain a bit what this does?

Without totally understanding it, would be tempted to replace it by:
for (i, b) in pairs(buttons)

Thank you.

I think a straightforward translation would be "Construct an (ordinal index, value) tuple for each entry in buttons and return at most the same number of these as their are fields in JSButtonState"

pairs and enumerate do the same thing for an array, so that would be a valid substitution. I wanted to ensure a number since the field name construction needs a number, so enumerate seemed more natural. take is there to prevent generating more field names than exist in JSButtonState . Another way to do this would be to add a test and break to the loop.

1 Like