Submitted by anonymous (Sun Apr 21 18:04:53 UTC 2002)
xxx: yyy<br>
:xxx => yyy.<br>
obj.do_something :some_arg => value1, :some_other_arg => value 2<br>
obj.do_something some_arg: value1, some_other_arg: value2<br>
a_hash = {<br> :if => "page 4",<br> :return => "page 5"<br> }<br>
a_hash = {<br> if: "page 4"<br> return: "page 5"<br> }<br>
(*xxx).field (in Ruby: :xxx => yyy)<br>
xxx->field (in Ruby?: xxx: yyy)<br>
Rationnal:
1) xxx: yyy is shorter than :xxx => yyy<br> 2) Promote the usage of symbols (efficient)<br> 3) Compares well to similar constructs in some other languages that have either "named arguments" or "named values" (or both)<br> 4) Natural, xxx: yyy is the syntax used in many internet protocols where the name of an attribute/field/element is followed by ":" and then the value of that attribute/field/element.<br>
Difficulties:
I don't know for sure but there might be some conflicts with the "?:" ternary operator. Example: (a ? b:c) and (a ? b:c : d:e). However in this case I don't think that => would be considered valid either: (a ? :b => c : :d => e) but I may be wrong.<br> I don't know for sure what can follow ":" in :xxx today. Ideal any xxx that is valid in :xxx should be ok in the xxx: form too. <br>
Implementation:
The implementation requires some look ahead (at lexical level), not much probably. i.e. What may first appear has a reference to a local variable xxx or a function xxx turns out to be the xxx symbol (when ":" is encountered). When that happens, "=>" should be pushed back in the input stream (that later one is easy I guess).<br> The implementation could focus on the simple cases first, when xxx is an identifier, and address more complex cases (when xxx is something more complex then an identifier, an arbitrary expression) later.<br>
BTW: "foo", y: "bar" could also be a nice shorter [:x,"foo", :y,"bar"]. I think it is a common idiom in Lisp to have such lists with flat pairs of symbol + value. Some other languages have a "name" attached to every values.
keyword arguments and xxx: yyy shorter notation for :xxx => yyy work together well =>
Considering the fact that methods callable with keyword arguments are yet to be developed / something of the future (existing methods where not designed to be called this way), there is little pain in asking the developer to tag the arguments that are keyword arguments.
Today (without keyword arguments):
def drawline( x = O, y = 0, thick = false)<br> xxx<br> end<br>
Tomorrow with keyword argument (my proposal)
def drawline( x: 0, y: 0, thick: false )<br> xxx<br> end<br>
Rationnal for tagging keyword arguments using ":" postfix:
1) The look of the def is similar to the one of a call.<br> obj.drawline( x: 45, y: 55, thick: true) # call drawline method<br> 2) Specifying a default value makes more sense for keyword arguments than it does for unamed ones. Hence A) the "=" can be avoided, B) the bad looking form def m( x:, y:) where x and y have no default values will be rare (btw: it would mean that the argument is mandatory, not optional ; for aesthetic reasons an optional "x: mandatory" or "x: required" sugar may be permitted).<br> 3) Having some ":" inside the formal argument list makes it possible for the interpreter to know that a method expects keyword arguments. For such a method there is less need for the convenient hash object built when extra arguments are provided at call time. But such a convenient construction is still relatively easy to implement: built the hash with the values that remains after the first nth values, where nth matches the number of arguments (minus one, the one that will hold the hash). ex:<br>
def m( x: 0, y: 0, *args ) xxx end<br> obj.m( 2, 4, foo: "hello", bar: "world") # positional, not keyworded<br> obj.m( x: 2, y: 4, foo: "hello", bar: "world") # args gets foo & bar<br> obj.m( x: 2, y: 4) # args gets empty hash<br> obj.m( x: 2) # y gets 0, args gets empty hash<br> obj.m( y: 4) # x gets 0, args gets empty hash<br> obj.m( foo: "hello", bar: "world")<br> => exception, bad parameter, <br>expecting x:, y:.
In this last case, the interpreter could potentially do a better job and figure out that x: & y: should get their default value. It would have to build the hash first and then unshift the first elements of the hash *if* their key matches the name of one of the keyword arguments (pretty inefficient I'm afraid)<br>
obj.m( bar: "world", foo: "hello", x: 0)<br> => exception, bad parameter, expecting x:, y:.<br>
In this case the interpreter might still figure out the intend of the caller. However I would question how much readable/contrived this is. That keyword arguments should appear before hash entries seems a rather reasonable constraint.<br>
obj.m( 2, 4, :foo => "hello", :bar => "world")<br> obj.m( :x => 2, :y => 4, :foo => "hello", :bar => "world")<br> obj.m( :x => 2, :y => 4)<br> obj.m( :x => 2)<br> obj.m( :y => 4).<br>
There is no way a call with keyword arguments can be as efficient as a call with "positional" arguments. As a result, the language should make it easier to use positional arguments in most cases. keywords arguments should be used mostly when there are more than one optional argument. Else you design a language that promotes the use of inefficient constructs and this may have bad impacts on the success of such a language (that would be considered "slow" by people who don't known how much speed they are trading to get more flexibility and consequently make the wrong tradeoffs).
Jean-Hugues
jean_hugues_robert@yahoo.com
Comments | Current voting | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
Why no comments? (Dave, 2002-04-28 08:53:31)
Now I know that real keywords may be coming along at some point, and the need to create hashes to handle this kind of thing will evaporate, but in the mean time this seems to be a nice idea. Comments?
b/c Jean-Hugues was very complete... (, 2002-05-08 20:38:10)
But (, 2002-06-16 15:18:19)
?