It might be nice to support the C++ default-argument idiom. i.e. defining
f(x, y = 3, z = 0) = .....
would be equivalent to defining
f(x,y,z) = ....
f(x,y) = f(x,y,0)
f(x) = f(x,3,0)
as I find myself doing the latter a lot.
Is this different from keyword arguments (e.g. #485) with defaults?
Was about to chime on with probable dupe of #485 myself. See also the Options package.
Except I'm not suggesting keywords, just the "syntactic sugar" for multiple dispatch that @JeffBezanson mentioned in the thread.
Ah. That would be a nice compromise along the road to full keyword arguments.
Yep, this is totally separate from keyword arguments. Keyword arguments could coexist with this by using ; as a separator:
f(x, y = 3; key = 0) = ...
I fully support this, this is basically the only reason I use the Options package. Having it be able to be so much less verbose would be awesome.
Keyword arguments strike me as much more important and I'm not at all sure that having a short syntax for default values for positional arguments is worth that additional syntactic complexity.
I kind of agree with Stefan that adding a semicolon is a source of confusion. To me this approach could be a nice interim solution, but I would find it confusing to have semicolons have actual semantic content in the language.
@johnmyleswhite Don't semicolons already have "actual semantic content" in the language, e.g. for [1 2 3; 4 5 6]? Jeff's suggestion of using a semicolon as a separator between positional and keyword arguments seems reasonable to me---separators are what semicolons are naturally useful for.
[1 2 3; 4 5 6]
@StefanKarpinski I definitely sympathize with the instinct to say "no" to new language features. Add too much stuff, and the language turns into C++.
In this particular case, because of Julia's Matlab heritage the use of optional trailing arguments for functions is very idiomatic for Julia (see e.g. sum, round, open, ...). (In Matlab, optional trailing arguments is the oldest and still the easiest form of overloading.) Adding syntactic sugar for this has the advantages that:
round(x[, digits[, base]])
round(x, digits=0, base=10)
@stevengj: You're completely right that semicolons do have semantic content already in the language. And, now that I understand the proposal better, I quite like the idea of adding syntactic sugar to make it easier to use optional trailing arguments. But that liking depends on the fact that we don't have keyword arguments yet.
What I worry about is that it becomes very strange to have a mixture of (1) defaults for positional arguments and (2) defaults for keywords separated only by a semicolon. I suspect that will be confusing to new users who wouldn't understand why all of the "optional" arguments aren't keyword arguments. It may just be my lack of familiarity with the C++ idiom, but I'd like all optional arguments to be keyword arguments as soon as that mechanism is in place.
@johnmyleswhite So, when (if?) keyword arguments are supported, you would want functions like sum, round, and open in the standard Julia library to switch over to that style for their optional arguments? This would be a fairly extensive change.
I would like that, but agree that it's such an extensive change that it may be infeasible. I also am not sure that we'll have keyword arguments anytime soon, which is why I'm now onboard for some sort of interim solution.
Remember also that even if keyword arguments are implemented in Julia, optional positional arguments will always be supported because of multiple dispatch, so keywords can never supersede them entirely. That is, optional positional arguments are a feature you already have now, what I am suggesting is just syntactic sugar to make them a bit cleaner to code and document and to encourage them to be used in a consistent way.
My feeling is that optional positional arguments are cleaner for functions like round with one or two optional arguments. Keyword arguments are better for functions like plot with large numbers of arguments. So, it is nice if both will co-exist in the long term (e.g. via a semicolon separator as @JeffBezanson suggested).
Sorry to revive an old thread, but I don't find a discussion on why optional positional arguments are only possible at the end of positional argument list... do they have to?
E.g. print(io::IO=STDOUT, xs...) ?
The next question is probably what to do in:
f(x::X=1, y, z::Z=3) = .... With the current rules, it would define implicitly f(x::X, y, z::Z) = ..., f(x::X, y) = ..., and f(y) = ... : number of methods equals number of defaults plus 1. Why not define implicitly f(x::X, y, z::Z), f(x::X, y), f(y, z::Z), f(y) ? (number of methods equals 2 raised to the number of defaults) I see that the increased complexity for method dispatch may be an obstacle, as well as the complications when the set of generated methods is ambiguous... Are these complications the reason for not implementing optional positionals not at the end?
f(x::X=1, y, z::Z=3) = ...
f(x::X, y, z::Z) = ...
f(x::X, y) = ...
f(y) = ...
f(x::X, y, z::Z)
If you were to use such a feature, you'd have to be really careful to not introduce ambiguous method definitions, or we would need a new sense of method priority so that we can write code like
foo(a=1, b=2) = a*b
Pick the right definition of foo so that the result is 6, not 3. There are probably more complicated cases.
Yes, maybe it is best left to a macro, or with a different syntax to make it less easy to introduce ambiguity. I'm writing one currently wich uses := instead of = for specifying that two overloaded methods should be defined wrt this argument, e.g @default function print(io::IO:=STDOUT, x, y=1) ... end would literally define function print(io::IO, x, y=1) ... end and print(x, y=1) = print(STDOUT, x, y). What do you think of this API?
@default function print(io::IO:=STDOUT, x, y=1) ... end
function print(io::IO, x, y=1) ... end
print(x, y=1) = print(STDOUT, x, y)