How to replace/name booleans in fn args?

Hi,
I have some functions whose behavior is defined by a bunch of booleans, which means that when I call them I don't know which is which:

        let res = parse_1_param::<E, E2>(
            input,
            project,
            &mut pins,
            &mut pins_byname,
            &mut substrate,
            &mut params,
            &mut model,
            &mut mfactor,
            true, /*count_only*/
            &mut nb_params,
            &mut nb_pins,
            &mut nb_pins_byname,
            &mut nb_substrate,
            true,
            true,
            false,
            false,
            false,
            true,
            true,
            false,
            false,
            false,
            false,
            &mut implicit_param_names,
        )?;
  • I could add a comment on each true/false but this is error-prone (it won't survive a bad copy/paste).
  • I could define an enum for each argument:
enum ArgSub {
    WithSub,
    WithoutSub,
}

... but doing this for each one would add lots of noise to the function definition, plus I would need to add many use ...::ArgSub::* in files using it.

Is there a simpler idiomatic way to name my booleans at function definition time, without being too verbose ?

I would probably define a struct for the argument.

struct Parse1Params {
    with_sub: bool,
    with_foo: bool,
    with_bar: bool,
}

If you put #[derive(Default)] on it, people will be able to fill out only the fields that are true:

Parse1Params {
    with_sub: true,
    ..Default::default()
}
3 Likes

Ooh yes that's nice ! Thanks !

when I call them I don't know which is which

You might want to think about replacing the boolean with enum values. They're a lot more descriptive, and it encourages correctness because each enum type can only be used for the corresponding argument, with a compile error following (rather than a silent failure as is the case with a bunch of booleans) if e.g. an argument is omitted by accident, or if values are out of order.

In addition, as long as the number of variants for each enum type <=255, the runtime representation is as large as that of a boolean, so it's not even more expensive.

plus I would need to add many use ...::ArgSub::* in files using it.

As verbose as the result is, in general I recommend against this, for reasons of comprehensibility and maintainability.

1 Like

Yes you're right, but @alice 's solution is not bad, and it enables some kind of "inheritance" which is really neat in my case (I often call the same function with the same arguments excepted one):

    let args = ArgsFullParam {
        with_sub: true,
        with_wl: true,
        with_model: true,
        strict_wl: Options::get().strict_wl,
        with_off: true,
        with_ic3: true,
        with_ldd: true,
        ..Default::default()
    };
...
    if let Ok((input_afterbm, _)) = parse_1_param::<E, E2>(
        input,
        project,
        &mut pins,
        &mut pins_byname,
        &mut substrate,
        &mut params,
        &mut model,
        &mut mfactor,
        &mut nb_params,
        &mut nb_pins,
        &mut nb_pins_byname,
        &mut nb_substrate,
        ArgsFullParam {
            count_only: true,
            ..args
        },
        &mut implicit_param_names,
    ) {
...

Only one place to check the parameters set (DRY), it stays explicit, and changes are visible. I love it !

The 2 approaches are actually not mutually exclusive: they can be combined. If you did that, you'd get better readability when constructing your ArgsFullParam object.

1 Like

I'm not sure. That means:

  • defining one enum per argument
  • implementing Default for each one (and I can't simply derive it)
  • use each one instead of one struct when crossing files

Yes the pure function-calling part would be nicer, but there would be too much boilerplate for my taste beforehand. That would drown the interesting code part.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.