Multiple-choice (dropdown) arguments

Writing code in julia, I often encounter the need for an argument which can assume a number of different choices. E.g. in IndexFunArrays many functions (e.g. rr(mysize; offset=CtrFT)) have the offset parameter which can be a tuple or one of the following:
(CtrCorner, CtrEnd, CtrFFT, CtrFT, CtrMid, CtrRFFT, CtrRFT) which are all part of an abstract type Ctr.

My question is, whether this is the correct way to go, or wether julia already has a more fitting concept for multiple-choice arguments. For a set of arguments, which appears in multiple places, maybe this mechanism is good, but what about use-cases where this is really only needed for this one function?
E.g., would it not be nice to write start_viewer(data::AbstractArray, mode=choice("new", "add", "replace", default="new")) ?

Does such a mechanism exist? Is it worth writing one?
Ideally IDEs would support the mechanism, such that the programmer sees the choices when attempting to call the function.

2 Likes

I guess it doesn’t, otherwise it would be much, much easier, for example, to choose linetypes, colors, fonts, etc, in plots… particularly if the choices appear by tabbing in the REPL.

I think a good implementation of that would be a huge usability improvement.

This should be doable right? foo(a,b=\TAB could simply do a methods call, and then return a tree of the available abstract and concrete types. For deep trees I guess recursing through subtypes might be expensive? Where is the tab completion code?

1 Like

We could go the route of Bash completion. Base could define a function called autocomplete that takes a function and what is known about the current arguments (maybe in the form of an Expr) and suggest things. Then it is responsibility of each module to implement a specific version for their functions, otherwise a generic default is used, that may try to do the best based only on the parameter type annotations available (and maybe the default parameters of optional parameters too).

I guess the biggest problem is that this will be called from a context in which the type of the already written arguments is not known, i.e., it will be called from the IDE/editor/REPL, the REPL may even know something but there will be context where it does not.

We can ignore the other argument types for most functions I’d think, except for really overloaded functions from Base I don’t imagine it’ll ever be very high. Tab completion only works in the REPL right? I found the completion code I think, and I could take a stab at this. Is foo(a,b=\TAB already used somewhere?

But yes that’s a good idea I think on the Base.autocomplete. I’ll give a try prototyping the simple version above tomorrow (ignore other types, just look for that keyword), see if it works, and then give your idea a try.

1 Like

Oh but I see what you mean we could give invalid arguments if we don’t look at the others

1 Like

Your last example seems like it should probably be handled by an enum. Could then support tab completions for that enum probably.

Yes. Enum or maybe types, with all the subtypes belonging to a common type anchestor
Something like

createChoices("Linetype", "dashed", "dotted")

yielding the definition of the abstract type ::Linetype <: MultipleChoice and empty subtypes ::dashed and ::dotted .
A bad thing is that the function would generate types. This sounds more like a macro.

@choices LineType dashed dotted dot_dashed
@addchoice LineType bold

Does this make sense?

… this would avoid invalid arguments, since the specification in the function reads

function foo(linetype::Linetype)
end

I think a plain old enum works best @enum Line type opt1 opt2. An empty type could work too I suppose.

1 Like