From: Daniel Brockman Date: 2005-07-20T07:00:56+09:00 Subject: Re: RCR: required args after optional ones Eric Mahurin writes: >> Eric, what is your opinion on this? Do you think these >> should all be allowed? >> >> def foo(a, b=nil, c, d=nil, e) ... end > > don't like it - too ambiguous. Does b or d get assigned > when you have 4 args? I'd say it's obvious that b gets assigned, since the above case is very much alike this one: def foo(a, b=nil, d=nil) ... end It doesn't make sense to prioritize d over b. Anyway, it is difficult to see the usefulness of this without an actual example. >> def bar(a, b=nil, *c, d=nil, e) ... end > > also don't like it - too ambiguous. Does b or d get > assigned when you have 3 args? I agree, this one is ambiguous. But I think the obvious choice is to prioritize the arguments left of the splat. >> def baz(*a, b=nil, c=nil) ... end > > maybe. you could handle this if optional args have > priority over splats. I think that's intuitive. >> If so, then which variable, b or c, should be bound when >> invoking baz with one argument? The obvious answer is b, >> but you could argue that c makes more sense, since c is >> farthest from the splat. > > I was thinking c to be symmetrical with optionals coming > before the splat. I tend to agree. > I think the meat of this RCR should handle these cases: > > def f(a, b, c=c0, d=d0, y, z) ... end > > def f(a, b, *m, y, z) ... end > > def f(a, b, c=c0, d=d0, *m, y, z) ... end > > I think these are pretty clear: y and z get the last 2 > args and the rest of the args are handled as they are now. Yes, these cases are not only crystal-clear; they are also the ones that seem the most useful. > I think this would be a bit more controversial: > > def f(a, b, *m, w=w0, x=x0, y, z) ... end > > In this case, after grabbing a, b, y, and z from the args, > x would have priority over w and w over m. That would be > symmetrical with optional args coming before the splat, > but confusing. Especially when you might be confused as > to whether w or x should have priority (as you discussed > above). I agree, these cases are confusing. Maybe if we had an actual example of two optional arguments after the splat occuring naturally, it would become easier to grasp. > What case do you have where you want optional args after > the splat? This came up earlier in the thread: def foo(*args) options = args.last.class == Hash ? args.pop : {} args.each { |x| options[x] = true } ... end For a while I thought that could be expressed like so, def foo(*flags, options={}) flags.each { |x| options[x] = true } ... end but I later realized that was not a good example, because this version cannot handle cases like ‘foo :bar, :baz’. It would have to look like this, def foo(*flags, options={}) unless options.class == Hash flags.push options ; options = {} end flags.each { |x| options[x] = true } ... end which is actually worse than the original version. So I don't have any example of a case where optional arguments after the splat is useful — maybe there are none. If someone can think of a case, please speak up. I will think about it for a while. -- Daniel Brockman So really, we all have to ask ourselves: Am I waiting for RMS to do this? --TTN.