Flag Passing in Rogue

I just added a handy feature to Rogue: a named parameter passing mechanism that's focused primarily on the passing and receiving of logical (boolean) flags. It reduces the amount of code that must be written and makes coding more intuitive and self-documenting.

I use logical flag parameters quite often to enable or disable certain optional steps in a method, but it's hard to remember what flag means what, which order they come in, and what true means and what false means.

Consider this slightly contrived example of getting a directory listing:

local listing = File(".").listing( true, false )

Here true might mean "recursive" and false might mean "make it relative; don't include the entire absolute filepath in the result". Or maybe false means "make it absolute, don't use relative filepaths". And perhaps they're in the wrong order.

We check the method definition or the documentation to see:

method listing( recurse=false:Logical, 
    absolute=false:Logical )->String[]

Okay then. Buuuuut... really I find myself double-checking code like that much more often than I would like to.

Here's how we'd rewrite that method definition using named flag parameters in the formal sense:

method listing( &recurse, &absolute )->String[]

Pop an ampersand in front and it's shorthand for "make this a Logical with a default value of false" (and actually you can specify a default value with the syntax &recurse=true, &absolute=false).

Now on the calling end we can still write listing(false,true), but we could also write it in any of the following ways:

local listing = File(".").listing( &recurse )
local listing = File(".").listing( &recurse, &!absolute )
local listing = File(".").listing( &!absolute, &recurse )
local listing = File(".").listing( &recurse=true )
local listing = File(".").listing( &recurse, &absolute=false )

Flag arguments are prefixed with &. They are collected separately from the other arguments and the appropriate true or false values are added back in later.

This is essentially a named parameter system sitting on top of standard positional parameter system. A few final notes:

  1. Every given flag argument must match a flag parameter (though there can be fewer passed arguments than method parameters).

  2. Since calls are matched to methods before flag parameters are considered, a call must not be ambiguous at that point.

  3. Methods can be defined with any mix of flag parameters and standard parameters.

  4. Flag arguments can be used to call methods with standard parameters and standard arguments can be used to call methods with flag parameters because the flag passing mechanism is essentially just a shorthand notation.

  5. Flag passing actually works with any type of variable; we just need to explicitly specify the the type and default value of a parameter and then specify the value to pass in when using the flag argument syntax. For example, method random_real64( low=0.0:Real64, high=1.0:Real64 )->Real64 and gen.random_real64( &high=0.5 ).

  6. The syntax for flag passing was chosen because it was a) available in Rogue, and b) reminiscent of web page URL parameters (?a=true&b=false&c=7).