Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A comparison by example of keyword argument styles

6 views
Skip to first unread message

Brian Mitchell

unread,
Oct 21, 2005, 2:47:52 AM10/21/05
to
Hello fellow rubyists,

What I have bellow is what started as a post to RedHanded. It was
growing in size too rapidly so I decided to post here for all to see.
Sorry for starting yet another thread on these topics. It is rough so
please don't nit pick details. I don't want this to start a flame war
(though I can't do much about that now). I would rather see some ideas
on how to get the best of both worlds. Some of this won't come without
a compromise so keep that in mind. I apologize in advance if I did
make any grievous errors in my interpretations.

There is a matter of taste involved but beyond that there are a few
easy comparisons. I will try to keep this down to just that (though a
few may be on a grey line, I hope they are clear enough).

Let me cite Matz's slides first:
* Make method calls more descriptive
* Order free arguments

With that simple goal in mind, lets start the comparisons.

Sydney's argument scheme (s_ henceforth) is simple when you want to
reorder the arguments.

def s_f1(a,b,c) ... end
s_f1(b:2, a:1, c:3)

Matz's scheme (m_ from now on) allows this too:

def m_f1(a:,b:,c:) ... end
m_f1(b:2, a:1, c:3)

Ok. Not much difference right away no clear winner. Lets examine
another variation on calling these:

s_f1(1,2,3) # Simple. current behavior.
m_f1(1,2,3) # Error. No positional arguments.

This shows one point that goes to s_. It makes it easy to use keyword
args that still have position. However, Matz could consider to allow
keyword arguments to count as positional arguments and make this
example go away. It is up to him. +1 for s_ for now. The change would
force non keyword args to come before keyword args. simple enough.
Though I still don't see a good reason to share both positional and
keyword arguments (a good example would be of great help in this
discussion).

The next example will be a method that takes any number of key-worded arguments:

def m_f2(**keys) ... end
m_f2(k1: 1, k2: 2, k3: 3)

def s_f2(*args) ... end
s_f2(k1: 1, k2: 2, k3: 2)

That works but there are some complications that the s_ method starts
to see (the hidden ugly head). *args now gets an array with hash
(key-value) or a value with each entry. Ugly. Now something internal
is depending on how someone on the outside (away from the interface)
called it to see what it gets. I hope this is clear enough for you. +1
for m_.

How about mixing positional and keyword args?

def m_f3(p1, p2, k1:, k2:) ... end
def s_f3(p1, p2, k1, k2) ... end

*_f3(1,2,k1:3, k2: 4)

Not much difference. m_ requires the extra : to be added. This is
neither a plus or a minus as it can be easily argued both ways. No
winner. (I will argue it if needed but trust me one can look both
ways).

How about having a variable number of positional arguments and a set
number of keys?

def m_f4(*args, a:, b:)
m_f4(1,2,3,4,5,6,7,8, a:1, b:2) # misleading see bellow.

def s_f4(a, b, *args)
s_f4(1,2,3,4,5,6,7,8, a:1, b:2) # might have the same problem

The s_ example is nice. It show an intuitive behavior at first but
depending on implementation you can no longer pull a variable number
of key paris or you have the same semantic problem that the m_ one
has. If you use * at all that allows any number of arguments of any
type to be passed. Assuming the latter behavior (needed for *args to
work with delegation), then neither has any gain. I may be miss
understanding s_ at this point so please point it out.

How about having both keyword and positional arguments mixed in a
catch-all with *?

def m_f5(*args)
m_f5(1,2, a:3, b:4)

def s_f5(*args)
s_f5(1,2 a:3, b:4)

Well things start to contrast now. For s_ you get: [1,2, { :a => 3}, {
:b => 4}] if I understand correctly. m_ gives you [1,2, {:a => 3, :b
=> 4}]. I won't debate on which is better in this case. Most of this
is involved with opinion. However, if you want to look at positionals
alone and keys alone it is easy with m_ we now have the hash collected
at the end of *args and can use **keys if we want to. Not a huge plus
but a point to make things easy. It will minimize boilerplate code on
a method. I give m_ a +1, you may disregard it if you don't agree.

Now think about the above before we move on. Keep in mind that it is
not just another way to call a method but gives the method's interface
a richer meaning (like Matz's slide said).

Now for some more concrete examples of usage:

Say we have an object that we create from a class through some special
method. The some arguments are required while others may or may not be
there but the circumstances differ. Imagine that the list of
attributes that can be passed may become quite long so using default
arguments wouldn't be a very good idea. Or even further, the keys
might be passed to a second function. This would normally be odd code
to see but it shows how the nature of the two methods differ by quite
a bit in real use.

# Untested code. Could contain errors. At least I have an excuse this time.
class Pet
def self.m1_create(kind, name, **keys)
pet = Pet.allocate
pet.kind = kind
pet.name = name
case(kind)
when :ham
pet.weight = keys[:weight]
when :cat
pet.color = keys[:color]
when :dog
pet.color = keys[:color]
pet.breed = keys[:breed]
when :ruby
pet.facets = keys[:facets]
else
fail "Uknown kind of pet: #{kind}"
end
end

# Same as m1_ but with a different method argument style.
def self.m2_create(kind:, name:, **keys)
# Lazy me ;) They are the same otherwise anyway.
m1_create(kind,name,**keys)
end

def self.s_create(kind, name, *args)
pet = Pet.allocate
pet.kind = kind
pet.name = name
# Messy solution. There is probably a better one.
get = lambda {|sym|
args.find(lambda{{}}) {|e|
e.kind_of? Hash && e[sym]
}[sym]
}
case(kind)
when :ham
pet.weight = get[:weight]
when :cat
pet.color = get[:color]
when :dog
pet.color = get[:color]
pet.breed = get[:breed]
when :ruby
pet.facets = get[:facets]
else
fail "Uknown kind of pet: #{kind}"
end
end
end

Pet.m1_create(:ham, "selfish_ham", weight:2.3)
Pet.m2_create(kind: :cat, name: "cat43", color: :black)
Pet.s_create(:dog, "singleton", color: :brown, breed: :mini_pincher)
Pet.s_create(kind: :ruby, name: "JRuby", facets: 26)

My s_ method is messy and could probably be cleaned up but it still
serves a point. Savor the style for a bit. It might add more verbosity
but I think it gives us some good side effects for the small price
(IMHO again). I think some really good points can be made for both
side but my _feeling_ is that Ruby doesn't need another halfway there
feature (IMHO). Keyword arguments are serious things and should be
treated as part of your interface (IMHO). I feel that the semantics of
m_ are more clear than the at first simpler look of s_ (IMHO -- why
not just automatically append these till the end of my message). It is
a hard choice. We still have one more option that I know of, change
nothing. Hashes seem to get the job done for most people already. I
know I missed something so please add to this. If I made any errors
please correct them. Just avoid and unproductive and personal attacks
please.

Thanks for reading this far,
Brian.


Robert Klemme

unread,
Oct 21, 2005, 3:37:18 AM10/21/05
to

Wow! Quite a comprehensive discussion. Thanks for writing this far! :-)

I think I have to digest this a bit, here are some first reading thoughts:

- Example for mixing keyword and positional args: like you showed, pos
args for mandatory, keyword args for multiple optional values.

- I guess Sydney's argument scheme will cause serious performance
drawbacks if there are multiple keyword arguments because there is one
hash per pair.

- Mixing both styles for a single method feels not right in Ruby because
it seems more complicated than necessary (just look at the length of the
part of your discussion that deals with this). Stored procedures of RDBMS
can usually be called with parameters given either positional style *or*
keyword style (btw, without a difference in declaration) but not mixed. I
would only allow one of the two approaches.

- Personally I'd probably favour an approach which allows only one
calling style at a time. Variables that have no default values declared
will just be nil. Basically this would be the equivalent of this with
nicer syntax:

old:
def foo(h)
h[:length] * h[:width]
end

foo(:length => 10, :width => 20)

new:
def foo(length, width)
length * width
end
foo 10, 20
foo width:20, length:10

Disclaimer: these remarks might not be too well thought out.

Kind regards

robert

Christophe Grandsire

unread,
Oct 21, 2005, 4:12:55 AM10/21/05
to
Selon Brian Mitchell <bina...@gmail.com>:

>
> My s_ method is messy and could probably be cleaned up but it still
> serves a point. Savor the style for a bit. It might add more verbosity
> but I think it gives us some good side effects for the small price
> (IMHO again). I think some really good points can be made for both
> side but my _feeling_ is that Ruby doesn't need another halfway there
> feature (IMHO). Keyword arguments are serious things and should be
> treated as part of your interface (IMHO). I feel that the semantics of
> m_ are more clear than the at first simpler look of s_ (IMHO -- why
> not just automatically append these till the end of my message). It is
> a hard choice. We still have one more option that I know of, change
> nothing. Hashes seem to get the job done for most people already. I
> know I missed something so please add to this. If I made any errors
> please correct them. Just avoid and unproductive and personal attacks
> please.
>

Thanks for the post Brian. I want to say that I agree with your conclusion that
matz's proposal is right now the best one. As I said on RedHanded, it's indeed
a question of interface. Keyword arguments are, when looking at them from an
interface point of view, like Smalltalk or Objective-C's multiword methods:
keyword arguments are part of the *name* of the method (that's even stronger
than being part of its signature IMHO). Positional arguments are *not* part of
the name of the function. Their position is part of its signature, but that's
all. Mixing both styles, positional and keyword, is thus a bad idea IMHO. It's
mixing things that exist on different levels. Keyword arguments, being just a
part of the name of a method, must be explicitly marked as such by the
developer, and shouldn't be allowed to be left out by the user, just like you
can't leave out the name of a method.

Implicitly making all arguments keyword arguments is like implicitly making all
arguments names part of the name of the method: it is actually more restrictive
than having to explicitly mark the keyword arguments (then you can at least
choose which arguments are part of the name of the method and which not).
Adding to that the possibility to call keyword arguments in a positional way
and you get a recipe for disaster. If, as a developer, you want some arguments
to be keyword arguments, make them explicitly so: *mean* it. Having half-baked
semi-keyword-semi-positional arguments is like not being able to choose between
two desserts on the menu, after an already heavy dinner: choose one or the
other, but don't take both. Besides the higher check, there's quite a chance
you'd end up sick.
--
Christophe Grandsire.

http://rainbow.conlang.free.fr

It takes a straight mind to create a twisted conlang.


Christophe Grandsire

unread,
Oct 21, 2005, 5:33:32 AM10/21/05
to
Selon Robert Klemme <bob....@gmx.net>:

>
> - Mixing both styles for a single method feels not right in Ruby because
> it seems more complicated than necessary (just look at the length of the
> part of your discussion that deals with this). Stored procedures of RDBMS
> can usually be called with parameters given either positional style *or*
> keyword style (btw, without a difference in declaration) but not mixed. I
> would only allow one of the two approaches.
>

I'm afraid that would be too restrictive for Ruby. There are already cases (see
Rails for instance, as I learned it in another thread) where methods have
positional arguments followed by hash arguments, which may be advantagedly
replaced with positional arguments followed by keyword arguments. I think it
wouldn't fit with Ruby's dynamic argument passing to make positional and
keyword styles exclude each other.

On the other hand, you are right about one thing: if one is to allow all
arguments to be called either positionally or by keyword (the Sydney approach),
then the positional and keyword styles *must* exclude each other completely.
This is the only way we can prevent confusion.

However, I still think keyword arguments should be explicitly defined as such.

> - Personally I'd probably favour an approach which allows only one
> calling style at a time. Variables that have no default values declared
> will just be nil. Basically this would be the equivalent of this with
> nicer syntax:
>
> old:
> def foo(h)
> h[:length] * h[:width]
> end
>
> foo(:length => 10, :width => 20)
>
> new:
> def foo(length, width)
> length * width
> end
> foo 10, 20
> foo width:20, length:10
>

Although I feel it's a bit too restrictive for Ruby, I could settle for that if
implicit keyword arguments win the debate. But I still prefer explicit ones.

On a side note, has the {a : 10, b : 20} alternative syntax for hashes that I've
seen proposed a long time ago been adopted?

Daniel Schierbeck

unread,
Oct 21, 2005, 5:42:48 AM10/21/05
to
I still haven't given up on my own style :)

def foo(:a, :b, :c = 3, **keys); end

# these should all be valid
foo :a => 1, :b => 2 # current style
foo a: 1, b: 2 # matz' proposition
foo :a = 1, :b = 2 # my style :D


1) *Method definition*
I think named arguments should have the same
syntax as positional ones, just with a colon
in front of it.

def foo(a, b, :c, :d = "bar")

2) *Method calling*
I think matz' style is preferable in many cases,
but i still think the :key = value syntax should
be there.

h = Human.new "John Doe", :height = 178, :weight = 65 # metric ;)
car.drive to: LasVegas, :speed = 125


Cheers,
Daniel

Damphyr

unread,
Oct 21, 2005, 6:40:49 AM10/21/05
to
Daniel Schierbeck wrote:
> I still haven't given up on my own style :)
>
> def foo(:a, :b, :c = 3, **keys); end
>
> # these should all be valid foo :a => 1, :b => 2 # current style
> foo a: 1, b: 2 # matz' proposition foo :a = 1, :b = 2 #
> my style :D
snip

> 2) *Method calling* I think matz' style is preferable in many
> cases, but i still think the :key = value syntax should be there.
>
> h = Human.new "John Doe", :height = 178, :weight = 65 # metric ;)
> car.drive to: LasVegas, :speed = 125
I can't say I can contribute much to the theoretical discussion. I can
only say what my first impressions are (up until Brian's email I was a
helpless spectator in an incomprehensible discussion).
The :a syntax looks a lot like symbols, which is something I would
avoid, in order to avoid paragraphs in documentation explaining that "in
method declarations :x means keyword", "when calling methods :a=x is a
keyword parameter assignment while :a is a symbol parameter" etc.
Cheers,
V.-
--
http://www.braveworld.net/riva

____________________________________________________________________
http://www.freemail.gr - δωρεάν υπηρεσία ηλεκτρονικού ταχυδρομείου.
http://www.freemail.gr - free email service for the Greek-speaking.


Trans

unread,
Oct 21, 2005, 7:05:23 AM10/21/05
to
Why not a Parameters class. This would allow cool things like:

a = [ :a, :b, :c ]

def foo(a.to_parm) #as def foo(a,b,c)
#...
end

And it would be more useful in the def too (Although maybe this would
be a different class):

def foo(**parm)
p parm.arguments
p parm.named_arguments
p parm.block.call
end

foo(1,2,:a=>3){ "block" }

=> [1,2]
{:a=>3}
"block"

I'm not so keen on sticking with symbols in the parameters list for
named parameters. I think there's too much ':' run-on. Things like this
are aweful:

foo set: :vital, sort: :reverse, mod: :odds do |a: :express|
# ...
end

Short of getting a new demarker for Symbol, I think it would be much
better to do without them in parameters if possible. This would work
fine I think:

def foo( a, b, c, x=>nil, y=>nil, z=>nil )
# ...
end

The def can be a shortened too:

def foo( a, b, c, x=>, y=>, z=> )
# ...
end

And call them in the same way:

foo( 1, 2, 3, x=>8, y=>9, z=>10 )

Which is *almost* exactly what we do now with hash parameters.

T.

Daniel Berger

unread,
Oct 21, 2005, 7:10:46 AM10/21/05
to
Brian Mitchell wrote:
> Hello fellow rubyists,

<snip>

> Sydney's argument scheme (s_ henceforth) is simple when you want to
> reorder the arguments.
>
> def s_f1(a,b,c) ... end
> s_f1(b:2, a:1, c:3)
>
> Matz's scheme (m_ from now on) allows this too:
>
> def m_f1(a:,b:,c:) ... end
> m_f1(b:2, a:1, c:3)
>
> Ok. Not much difference right away no clear winner.

Ruby has always favored implicitness over explicitness. The fact that
I don't have to do anything explicitly in Sydney makes it the winner
IMHO.

> Lets examine
> another variation on calling these:
>
> s_f1(1,2,3) # Simple. current behavior.
> m_f1(1,2,3) # Error. No positional arguments.
>
> This shows one point that goes to s_. It makes it easy to use keyword
> args that still have position. However, Matz could consider to allow
> keyword arguments to count as positional arguments and make this
> example go away. It is up to him. +1 for s_ for now. The change would
> force non keyword args to come before keyword args. simple enough.
> Though I still don't see a good reason to share both positional and
> keyword arguments (a good example would be of great help in this
> discussion).
>
> The next example will be a method that takes any number of key-worded arguments:
>
> def m_f2(**keys) ... end
> m_f2(k1: 1, k2: 2, k3: 3)
>
> def s_f2(*args) ... end
> s_f2(k1: 1, k2: 2, k3: 2)
>
> That works but there are some complications that the s_ method starts
> to see (the hidden ugly head). *args now gets an array with hash
> (key-value) or a value with each entry. Ugly.

No, it's a single hash - [{:k1=>1, :k2=>2, :k3=>3}]. In Matz's
implementation, there is no '*args' afaik, only '**keys', which is
{:k1=>, :k2=>2, :k3=>3}.

> Now something internal
> is depending on how someone on the outside (away from the interface)
> called it to see what it gets. I hope this is clear enough for you. +1
> for m_.

I don't understand what you mean here.

> How about mixing positional and keyword args?
>
> def m_f3(p1, p2, k1:, k2:) ... end
> def s_f3(p1, p2, k1, k2) ... end
>
> *_f3(1,2,k1:3, k2: 4)
>
> Not much difference. m_ requires the extra : to be added. This is
> neither a plus or a minus as it can be easily argued both ways. No
> winner. (I will argue it if needed but trust me one can look both
> ways).
>
> How about having a variable number of positional arguments and a set
> number of keys?
>
> def m_f4(*args, a:, b:)
> m_f4(1,2,3,4,5,6,7,8, a:1, b:2) # misleading see bellow.
>
> def s_f4(a, b, *args)
> s_f4(1,2,3,4,5,6,7,8, a:1, b:2) # might have the same problem
>
> The s_ example is nice. It show an intuitive behavior at first but
> depending on implementation you can no longer pull a variable number
> of key paris or you have the same semantic problem that the m_ one
> has.

Huh? What makes you think the number of key pairs is limited?

> If you use * at all that allows any number of arguments of any
> type to be passed. Assuming the latter behavior (needed for *args to
> work with delegation), then neither has any gain. I may be miss
> understanding s_ at this point so please point it out.
>
> How about having both keyword and positional arguments mixed in a
> catch-all with *?
>
> def m_f5(*args)
> m_f5(1,2, a:3, b:4)
>
> def s_f5(*args)
> s_f5(1,2 a:3, b:4)
>
> Well things start to contrast now. For s_ you get: [1,2, { :a => 3}, {
> :b => 4}] if I understand correctly. m_ gives you [1,2, {:a => 3, :b
> => 4}].

No. They are identical.

> I won't debate on which is better in this case. Most of this
> is involved with opinion. However, if you want to look at positionals
> alone and keys alone it is easy with m_ we now have the hash collected
> at the end of *args and can use **keys if we want to. Not a huge plus
> but a point to make things easy. It will minimize boilerplate code on
> a method. I give m_ a +1, you may disregard it if you don't agree.
>
> Now think about the above before we move on. Keep in mind that it is
> not just another way to call a method but gives the method's interface
> a richer meaning (like Matz's slide said).

The ability to inspect positionals alone or keywords alone *will* be
possible, via Behaviors.

<snip>

No, you would use Behaviors. This hasn't been entirely fleshed out
yet, but it will likely look like this.

def self.s_create(kind, name, *args)
...
keys = KeywordBehavior.keyword_arguments
...
end

So, in that particular example, Sydney takes one more line. I think
there will also be KeywordBehavior.positional_arguments and
KeywordBehavior.arguments. The former would be positional arguments
only, while the latter would be all arguments.

Note that this provides equal or greater flexibility with regards to
delegation, not less, as Matz suggested in one RedHanded comment.

I've committed the test suite to the SVN repository if folks want to
get a clearer idea of how things work (so far). It's
"test_keyword_arguments.rb" under test/ruby.

Regards,

Dan

Daniel Berger

unread,
Oct 21, 2005, 7:14:27 AM10/21/05
to
Trans wrote:
> Why not a Parameters class. This would allow cool things like:
>
> a = [ :a, :b, :c ]
>
> def foo(a.to_parm) #as def foo(a,b,c)
> #...
> end
>
> And it would be more useful in the def too (Although maybe this would
> be a different class):
>
> def foo(**parm)
> p parm.arguments
> p parm.named_arguments
> p parm.block.call
> end
>
> foo(1,2,:a=>3){ "block" }
>
> => [1,2]
> {:a=>3}
> "block"

Sydney will accomplish this via behaviors:

# This is *not* finalized
def foo(*parm)
p KeywordBehavior.arguments
p KeywordBehavior.keyword_arguments
end

Abstracting it out to a generic "Parameter" behavior is something I
hadn't thought of, but knowing Evan, it just might be possible. :)

Regards,

Dan

David A. Black

unread,
Oct 21, 2005, 7:22:29 AM10/21/05
to
Hi --

On Fri, 21 Oct 2005, Daniel Berger wrote:

> Brian Mitchell wrote:
>> Hello fellow rubyists,
>
> <snip>
>
>> Sydney's argument scheme (s_ henceforth) is simple when you want to
>> reorder the arguments.
>>
>> def s_f1(a,b,c) ... end
>> s_f1(b:2, a:1, c:3)
>>
>> Matz's scheme (m_ from now on) allows this too:
>>
>> def m_f1(a:,b:,c:) ... end
>> m_f1(b:2, a:1, c:3)
>>
>> Ok. Not much difference right away no clear winner.
>
> Ruby has always favored implicitness over explicitness. The fact that
> I don't have to do anything explicitly in Sydney makes it the winner
> IMHO.

I don't agree. If I write this:

def meth(a,b,c) ... end

I expect to be "allowed" to rename my parameters at will without
breaking any calling code. I'd even expect to be allowed to change,
say, (a,b,*c) to *args if I felt there was a good reason to.

I don't want my choice of local variable names to be coupled to
calling code. If I offer keywords or hash keys, that means I've
decided that I *do* want to publish those names, and commit to them.
Otherwise I consider them strictly the method's business, not the
caller's.


David

--
David A. Black
dbl...@wobblini.net


Christophe Grandsire

unread,
Oct 21, 2005, 7:38:13 AM10/21/05
to
Selon Damphyr <dam...@freemail.gr>:

> I can't say I can contribute much to the theoretical discussion. I can
> only say what my first impressions are (up until Brian's email I was a
> helpless spectator in an incomprehensible discussion).
> The :a syntax looks a lot like symbols, which is something I would
> avoid, in order to avoid paragraphs in documentation explaining that "in
> method declarations :x means keyword", "when calling methods :a=x is a
> keyword parameter assignment while :a is a symbol parameter" etc.

I agree. Also, the (a: "foo") syntax looks a lot like Smalltalk's named
arguments, and that gives it instant recognition.

Christophe Grandsire

unread,
Oct 21, 2005, 7:54:23 AM10/21/05
to
Selon "David A. Black" <dbl...@wobblini.net>:

> >
> > Ruby has always favored implicitness over explicitness. The fact that
> > I don't have to do anything explicitly in Sydney makes it the winner
> > IMHO.
>
> I don't agree. If I write this:
>
> def meth(a,b,c) ... end
>
> I expect to be "allowed" to rename my parameters at will without
> breaking any calling code. I'd even expect to be allowed to change,
> say, (a,b,*c) to *args if I felt there was a good reason to.
>
> I don't want my choice of local variable names to be coupled to
> calling code. If I offer keywords or hash keys, that means I've
> decided that I *do* want to publish those names, and commit to them.
> Otherwise I consider them strictly the method's business, not the
> caller's.
>

Amen. As I keep saying, it's a matter of interface. If you allow implicit
keyword arguments, you're suddenly mixing interface and implementation, and
that is *wrong* (in the sense that it is difficult to maintain, and it breaks
the promise of encapsulation). However, if you explicitly decide that some
argument is a keyword argument, you have *consciously* made it part of the
interface (I'd rather say part of the very *name* of the method), so you can
still maintain the separation between interface and implementation to the level
you want as a developer.

And I disagree that Ruby favours implicitness. It favours dynamicity, openness,
reflection, convention above configuration (and that's more a style common to
many Rubyists and well exemplified in Rails). But that doesn't imply
implicitness (pardon the pun, it was unintented). If anything, the fact that
Ruby is strongly typed, even if dynamically typed, and hardly does any implicit
casting (except among numbers, especially between Fixnum and Bignum), should be
indicative that Ruby, if anything, *does not favour implicitness*.

Berger, Daniel

unread,
Oct 21, 2005, 9:43:49 AM10/21/05
to
> -----Original Message-----

> Amen. As I keep saying, it's a matter of interface. If you
> allow implicit keyword arguments, you're suddenly mixing
> interface and implementation, and that is *wrong* (in the
> sense that it is difficult to maintain, and it breaks the
> promise of encapsulation). However, if you explicitly decide
> that some argument is a keyword argument, you have
> *consciously* made it part of the interface (I'd rather say
> part of the very *name* of the method), so you can still
> maintain the separation between interface and implementation
> to the level you want as a developer.

The separation between implementation and behavior you make here is lost
the moment you commit to supporting a keyword argument for any given
method, regardless of the fact that it was an explicit, conscious
choice. Once chosen, you're still beholden to that keyword name forever
unless you want to break backwards compatability. I think the perceived
freedom is an illusion.

There seems to be this fear of using an argument name, and then later
changing your mind about what the argument name should be called. To
that I reply that, even with the explicit syntax, this issue does not go
away. I would also say that all the implicit syntax does is force you
to think more up front about your API and naming conventions. With
Sydney, at least you can resort to positional parameters in the unlikely
event that the argument name did change, something you can't do with
Matz's current proposal afaik.

Regards,

Dan


David A. Black

unread,
Oct 21, 2005, 9:57:16 AM10/21/05
to
Hi --

On Fri, 21 Oct 2005, Berger, Daniel wrote:

>> -----Original Message-----
>
>> Amen. As I keep saying, it's a matter of interface. If you
>> allow implicit keyword arguments, you're suddenly mixing
>> interface and implementation, and that is *wrong* (in the
>> sense that it is difficult to maintain, and it breaks the
>> promise of encapsulation). However, if you explicitly decide
>> that some argument is a keyword argument, you have
>> *consciously* made it part of the interface (I'd rather say
>> part of the very *name* of the method), so you can still
>> maintain the separation between interface and implementation
>> to the level you want as a developer.
>
> The separation between implementation and behavior you make here is lost
> the moment you commit to supporting a keyword argument for any given
> method, regardless of the fact that it was an explicit, conscious
> choice. Once chosen, you're still beholden to that keyword name forever
> unless you want to break backwards compatability. I think the perceived
> freedom is an illusion.

But that's the point: keyword arguments represent a decision to name
your arguments. It's just like a hash. If I say that my method takes
a hash:

:first_name => ..., :last_name => ...

then of course I've committed to those keys, and can't change them
whenever I feel like it.

I just don't see why it has to be a winner-take-all situation, when
it's perfectly possible to have both keywords arguments and
"uncoupled" positional arguments.

> There seems to be this fear of using an argument name, and then later
> changing your mind about what the argument name should be called.

It's not a fear: it's a right :-) Having local variable names always
be part of the API just doesn't make sense to me at all.

> To that I reply that, even with the explicit syntax, this issue does
> not go away. I would also say that all the implicit syntax does is
> force you to think more up front about your API and naming
> conventions. With Sydney, at least you can resort to positional
> parameters in the unlikely event that the argument name did change,
> something you can't do with Matz's current proposal afaik.

But that means the caller has to keep track of whether or not the
maintainer of the code has change variable names. I don't want to be
on either end of that. It could be a refactoring and/or maintenance
nightmare.

Trans

unread,
Oct 21, 2005, 10:11:22 AM10/21/05
to

Berger, Daniel wrote:

> The separation between implementation and behavior you make here is lost
> the moment you commit to supporting a keyword argument for any given
> method, regardless of the fact that it was an explicit, conscious
> choice. Once chosen, you're still beholden to that keyword name forever
> unless you want to break backwards compatability. I think the perceived
> freedom is an illusion.
>
> There seems to be this fear of using an argument name, and then later
> changing your mind about what the argument name should be called. To
> that I reply that, even with the explicit syntax, this issue does not go
> away. I would also say that all the implicit syntax does is force you
> to think more up front about your API and naming conventions. With
> Sydney, at least you can resort to positional parameters in the unlikely
> event that the argument name did change, something you can't do with
> Matz's current proposal afaik.

I must say, I was leaning with David, but these are good counter
arguments.

Perhaps we should just sing a song and "Let's Call The Whole Thing
Off". If keywords integrate the interface too tightly with the code,
then why tie them to the interface? Also, I imagine there many be many
more keyword arguments then ordered args, this will make for some very
LONG constructors:

def stadium( height:, seating_capacity:, location:, color:, sports:,
concessions:, extra_features:, indoor:, yadayadayada: )

So maybe just treat named parameters like blocks. You can have em or
not. But you don't need to define them in the interface. Currently I do
a lot of

def( *args )
keys = args.last.is_a?(Hash) ? args.pop : {}
a,b,c = *args

If I could just do

def( a, b, c, **keys )
...

I'd be happy enough.

T.

P.S. But I don't much care for double character '**'. Single character
would be better. Perhaps '#' or '%'.

Christophe Grandsire

unread,
Oct 21, 2005, 10:17:16 AM10/21/05
to
Selon "Berger, Daniel" <Daniel...@qwest.com>:

>
> The separation between implementation and behavior you make here is lost
> the moment you commit to supporting a keyword argument for any given
> method, regardless of the fact that it was an explicit, conscious
> choice.

I happen to think that the fact that it was an explicit, conscious choice does
make a difference.

Once chosen, you're still beholden to that keyword name forever
> unless you want to break backwards compatability.

Yes, but you chose for it. In your implementation, the language chooses already
for the developer. Sorry, but although a language always makes some choices for
the developer, there are some that are more justified than others. This is one
in my opinion that is not justified.

I think the perceived
> freedom is an illusion.
>

That's your opinion. In my opinion it's very real.

> There seems to be this fear of using an argument name, and then later
> changing your mind about what the argument name should be called. To
> that I reply that, even with the explicit syntax, this issue does not go
> away.

No, but at least you chose for the situation.

I would also say that all the implicit syntax does is force you
> to think more up front about your API and naming conventions.

Too much in my opinion. Argument names shouldn't be part of the API unless one
explicitly chooses it that way. Also, having to think upfront about all the
details of your implementation, just to get a stable API, is not how software
is built. That's the main thing I don't like about your proposal: changing a
method's implementation under Sydney's implementation is much more likely to
change the API of the method than under Matz's proposal, *because you never
know who will call your arguments positionally and who will call them by
keyword.* Despite what you may think, the loss of freedom for the developer is
very real, and the coupling between interface and implementation far too strong
to be comfortable.

Sorry, but when I have positional arguments, I only want to have to worry about
their position for the API, and when I have keyword arguments, I only want to
have to worry about their names for the API. In your proposal I have to worry
about both, for all arguments. You seem to think that your proposal adds the
advantages of both styles. In my opinion it only adds together their drawbacks.
The advantages of keyword arguments disappear when there's a chance that someone
will call them positionally, and the advantages of positional arguments
disappear when there's a chance that someone will use them with keywords.

With
> Sydney, at least you can resort to positional parameters in the unlikely
> event that the argument name did change, something you can't do with
> Matz's current proposal afaik.

And then the programmer changes the order of the arguments because it fits
better the meaning of the definition and you lose anyway. Sorry, but I don't
think that's a gain. If the developer changes the API, change your program.
Such kind of stop-gap measure brings nothing but trouble. I think it only
encourages sloppiness, both for the developer and the user.

Berger, Daniel

unread,
Oct 21, 2005, 10:32:20 AM10/21/05
to
> -----Original Message-----
> From: Trans [mailto:tran...@gmail.com]
> Sent: Friday, October 21, 2005 8:12 AM
> To: ruby-talk ML
> Subject: Re: A comparison by example of keyword argument styles

<snip>

> Perhaps we should just sing a song and "Let's Call The Whole
> Thing Off".

Heh. Thought about it.

> If keywords integrate the interface too tightly
> with the code, then why tie them to the interface? Also, I
> imagine there many be many more keyword arguments then
> ordered args, this will make for some very LONG constructors:
>
> def stadium( height:, seating_capacity:, location:, color:,
> sports:, concessions:, extra_features:, indoor:, yadayadayada: )
>
> So maybe just treat named parameters like blocks. You can
> have em or not. But you don't need to define them in the
> interface. Currently I do a lot of
>
> def( *args )
> keys = args.last.is_a?(Hash) ? args.pop : {}
> a,b,c = *args
>
> If I could just do
>
> def( a, b, c, **keys )
> ...
>
> I'd be happy enough.

I'm glad you brought this example up. What do you do when you have a
ton of accessors in your class? I have just such a case with the Format
class in the spreadsheet package, where you have "font_name",
"font_size", "border_color", etc. About 30 accessors I think.

The solution here is NOT keywords arguments (regardless of
implementation), where you would end up with ridiculously long
constructors, as you mentioned. It's the old "yield self if
block_given?" trick:

class Format
attr_accessor :font_color, :font_size, :bold # ...
def initialize
yield self if block_given?
end
end

format = Format.new do |f|
f.font_color = "blue"
f.font_size = 10
f.bold = true
...
end

Regards,

Dan


Trans

unread,
Oct 21, 2005, 10:35:47 AM10/21/05
to
"Ah, to Hek with interfaces. They're overrated anyways!", says Typo the
Duck. "You can Duckument cant you?"

def phooey
unless %how
"This thing quacks like a #{%1}."
else
"This thing #{%how} like a #{%1}."
end
end

phooey( "duck" )
=> "This thing quacks like a duck."

phooey( "duck", how=>"looks" )
=> "This thing looks like a duck."

:-)

T.

Kevin Ballard

unread,
Oct 21, 2005, 10:54:02 AM10/21/05
to
I'd quote stuff, but I'd be pulling from too many messages that it
would take forever ;)

Anyway, here are my thoughts on the subject:

I really would like to see keyword arguments done right. Sydney's style
of all arguments are implicit keyword arguments I think is terrible.
The points above about being able to rename your args without worrying
about calling code is good, but also I believe that implicit keyword
arguments can make for inconsistent calling conventions.

Basically, keyword arguments should be explicitly defined. This is akin
to defining the name of the method - you're making a conscious API
decision. Implicit keywords makes every single argument an API decision
when it's simply not necessary.

In terms of syntax, I was perfectly happy with the

m_f1(1, 2, a:3, b:4)

syntax until it was pointed out that this looks really terrible when
you pass symbols, as in

m_f1(1, 2, a: :foo, b: :bar)

As was also mentioned above, I believe the best syntax is to borrow the
current implicit hash syntax, as in

m_f1(1, 2, a=>:foo, b=>:bar)

This has several advantages. First off, it's a syntax that everybody is
familiar with. Secondly, if we add a backwards-compatibility feature of
treating

m_f1(1, 2, :a => :foo, :b => :bar)

the same as the keyword version (i.e. with "a" and "b" isntead of ":a"
and ":b"), then it lends itself really well to making existing code use
keyword arguments. Any code that currently uses the implicit hash to
mock keywords can have the method redefined to use explicit keyword
arguments and the calling code will remain untouched, so the API will
remain the same. This I think is a huge plus. In terms of specifics for
this syntax, I think that methods without defined keyword arguments
should continue to use the implicit hash behaviour, and methods with
defined keyword arguments should no longer accept the implicit hash,
but rather if you want dynamic keyword arguments you should specify the
**args argument to grab all unknown keyword arguments. This way
existing code will work as-is, and can be slowly converted to use
keyword arguments wherever appropriate. This will also help with
methods that take mock keyword arguments because as soon as they're
changed to use explicit keyword arguments, then they automatically will
get argument checking on the keyword names, which can help people
trying to call that code (i.e. it will tell you if you typoed when
calling the method [unless, of course, the method takes arbitrary
keywords as well via **args]).

The only thing I'm not sure about right now is the proper syntax for
defining them. I don't mind the look of

def m_f1(foo, bar, a:, b:)

except that it no longer makes sense once you're using => instead of :
in the calling conventions. Maybe we could do something like

def m_f1(foo, bar, :a, :b)

or grab another symbol and use that, like

def m_f1(foo, bar, %a, %b)

I personally prefer the look of the first (:a, :b).

Sean O'Halpin

unread,
Oct 21, 2005, 10:57:35 AM10/21/05
to
On 10/21/05, David A. Black <dbl...@wobblini.net> wrote:
> I expect to be "allowed" to rename my parameters at will without
> breaking any calling code. I'd even expect to be allowed to change,
> say, (a,b,*c) to *args if I felt there was a good reason to.

I'm with you on this David. I find myself doing (a,b,*args) => (*args)
quite often.

Regards,

Sean


Yukihiro Matsumoto

unread,
Oct 21, 2005, 10:58:54 AM10/21/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"


on Fri, 21 Oct 2005 18:46:59 +0900, Daniel Schierbeck <daniel.s...@gmail.com> writes:

|1) *Method definition*
| I think named arguments should have the same
| syntax as positional ones, just with a colon
| in front of it.
|
| def foo(a, b, :c, :d = "bar")

Why with a colon in front of it instead of right after it?

|2) *Method calling*
| I think matz' style is preferable in many cases,
| but i still think the :key = value syntax should
| be there.

Why should be?

matz.


Yukihiro Matsumoto

unread,
Oct 21, 2005, 11:10:19 AM10/21/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Fri, 21 Oct 2005 20:12:08 +0900, "Daniel Berger" <djbe...@gmail.com> writes:

|Ruby has always favored implicitness over explicitness. The fact that
|I don't have to do anything explicitly in Sydney makes it the winner
|IMHO.

Too much implicitness makes code cryptic. Too much explicitness makes
code verbose. It's a matter of balance.

By the way, how do you delegate the whole arguments (including keyword
arguments) in your style? Using KeywordBehavior?

Besides, what would happen for the following code?

def foo(*args)
# how do you delegate arguments?
bar(*args)
end

def bar(a,b,c)
p [a,b,c]
end

foo(1,a:2,c:3)

and

class Foo
def foo(a,b,c)
p [a,b,c]
end
end
class Bar<Foo
# what if argument names differ?
def foo(d,e,f)
super
end
end
Bar.new.foo(d:1,e:2,f:3)

matz.


Daniel Berger

unread,
Oct 21, 2005, 11:12:54 AM10/21/05
to
Christophe Grandsire wrote:

<snip>

> Yes, but you chose for it. In your implementation, the language chooses already
> for the developer. Sorry, but although a language always makes some choices for
> the developer, there are some that are more justified than others. This is one
> in my opinion that is not justified.

But it *is* you who chooses it when you choose the parameter name. I don't
feel the loss of control you seem to feel. I guess we're getting into
programmer psychology here. ;)

>
> I would also say that all the implicit syntax does is force you
>
>>to think more up front about your API and naming conventions.
>
>
> Too much in my opinion. Argument names shouldn't be part of the API unless one
> explicitly chooses it that way. Also, having to think upfront about all the
> details of your implementation, just to get a stable API, is not how software
> is built.

*All* of the details of the implementation? No, just the parameter names.
That's a far cry from "all" IMO.

> That's the main thing I don't like about your proposal: changing a
> method's implementation under Sydney's implementation is much more likely to
> change the API of the method than under Matz's proposal, *because you never
> know who will call your arguments positionally and who will call them by
> keyword.* Despite what you may think, the loss of freedom for the developer is
> very real, and the coupling between interface and implementation far too strong
> to be comfortable.

My reply to this would be that major refactorings usually break backwards
compatability anyway, and the positional versus keyword argument becomes moot.
That, or you have to jump through extra hoops to maintain it.

> Sorry, but when I have positional arguments, I only want to have to worry about
> their position for the API, and when I have keyword arguments, I only want to
> have to worry about their names for the API. In your proposal I have to worry
> about both, for all arguments. You seem to think that your proposal adds the
> advantages of both styles. In my opinion it only adds together their drawbacks.
> The advantages of keyword arguments disappear when there's a chance that someone
> will call them positionally, and the advantages of positional arguments
> disappear when there's a chance that someone will use them with keywords.

We'll have to agree to disagree. :)

>
> With
>
>>Sydney, at least you can resort to positional parameters in the unlikely
>>event that the argument name did change, something you can't do with
>>Matz's current proposal afaik.
>
>
> And then the programmer changes the order of the arguments because it fits
> better the meaning of the definition and you lose anyway.

You lose with either implementation if positional parameters change (or even
current Ruby).

> Sorry, but I don't
> think that's a gain. If the developer changes the API, change your program.
> Such kind of stop-gap measure brings nothing but trouble. I think it only
> encourages sloppiness, both for the developer and the user.

Encourages sloppiness? I think it will have the opposite effect.

I should also point out that Sydney *could* make keyword arguments optional by
resorting to a more explicit behavior style API, e.g.

class Foo
behavior KeywordBehavior
def initialize(x, y, z)
...
end
end

This would give all methods of class Foo implicit keyword parameters. But,
perhaps we could make it even more granular (though I'm not certain without
asking Evan). I'm just making stuff as I go here, but perhaps this:

class Foo
behavior KeywordBehavior
def bar(x, y, z)
...
end
def baz(a, b = 4)
...
end

# Add keyword support for parameter 'z' in method 'bar'
KeywordBehavior.keyword_argument(:bar => "z")
end

Ok, it gets pretty verbose when you get that granular, but I thought I would
toss it out there.

Regards,

Dan


Daniel Berger

unread,
Oct 21, 2005, 11:44:58 AM10/21/05
to
Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: A comparison by example of keyword argument styles"
> on Fri, 21 Oct 2005 20:12:08 +0900, "Daniel Berger" <djbe...@gmail.com> writes:
>
> |Ruby has always favored implicitness over explicitness. The fact that
> |I don't have to do anything explicitly in Sydney makes it the winner
> |IMHO.
>
> Too much implicitness makes code cryptic. Too much explicitness makes
> code verbose. It's a matter of balance.
>
> By the way, how do you delegate the whole arguments (including keyword
> arguments) in your style? Using KeywordBehavior?
>
> Besides, what would happen for the following code?
>
> def foo(*args)
> # how do you delegate arguments?
> bar(*args)
> end
>
> def bar(a,b,c)
> p [a,b,c]
> end
>
> foo(1,a:2,c:3)

Not allowed because redefinition of the same parameter raises an error. Here
you're trying to define 'a' twice, once as the first positional argument, once
as a named parameter.

For purposes of this argument, though, let's say you did this:

foo(b:1, a:2, c:3)

Then, if we inspect '*args' in foo, it looks like [{:b=>1, :a=>2, :c=>3}]

For now, we're toying with the idea of an explicit behavior call to handle
splat args in this case. So, the method definition would look like this:

def foo(*args)
bar(*KeywordBehavior.arguments) # Would pass 2, 1, 3
end

Yes, it's uglier. How does it work in your implementation? I'm curious to know
how you preserve argument order.

> and
>
> class Foo
> def foo(a,b,c)
> p [a,b,c]
> end
> end
> class Bar<Foo
> # what if argument names differ?
> def foo(d,e,f)
> super
> end
> end
> Bar.new.foo(d:1,e:2,f:3)
>
> matz.
>
>

We discussed this somewhat last night. There are a couple of possible routes
to take.

1) Insist that parameter names must match, and raise an error.
2) Pass the arguments positionally.

I think we're still undecided if I recall correctly.

Let me ask you the same thing. What happens here with your implementation?

class Foo
def foo(a:, b:, c:)
p [a,b,c]
end
end

class Bar < Foo
def foo(d:, e:, f:)
super
end
end

Bar.new.foo(f:3, e:2, d:1)

Regards,

Dan

Brian Mitchell

unread,
Oct 21, 2005, 12:31:46 PM10/21/05
to

Thanks for the reply. This clears the picture up a bit for me.

Brian.


David A. Black

unread,
Oct 21, 2005, 1:22:32 PM10/21/05
to
Hi --

On Fri, 21 Oct 2005, Trans wrote:

> So maybe just treat named parameters like blocks. You can have em or
> not. But you don't need to define them in the interface. Currently I do
> a lot of
>
> def( *args )
> keys = args.last.is_a?(Hash) ? args.pop : {}
> a,b,c = *args
>
> If I could just do
>
> def( a, b, c, **keys )
> ...
>
> I'd be happy enough.
>
> T.
>
> P.S. But I don't much care for double character '**'. Single character
> would be better. Perhaps '#' or '%'.

def meth(a,b,#c) that's a comment
def meth(a,b,%w_w) # this one is ambiguous

Trans

unread,
Oct 21, 2005, 2:07:03 PM10/21/05
to

David A. Black wrote:
> > P.S. But I don't much care for double character '**'. Single character
> > would be better. Perhaps '#' or '%'.
>
> def meth(a,b,#c) that's a comment

puts "but this is #{not}"

> def meth(a,b,%w_w) # this one is ambiguous

did you mean?

def meth(a,b,%w_w_) # this one is ambiguous

Yes, you're right.

In either case, I'd just prefer on one character rather than two
(reduce Perliness). But it's not a big deal.

Thanks,
T.

Brian Mitchell

unread,
Oct 21, 2005, 2:08:19 PM10/21/05
to
Hello again,

I am updating my original post with more information, namely some
corrections for s_ and some new discussion at the bottom. I am will
say again that the stuff bellow probably still contains errors but I
hope that it is at least more accurate than my original. I left all
the original text there so we could have a nice comparison of now and
then. It also serves as a good example of how something might work for
an implementation that differs in a way that is congruent to my
original post.

On 10/21/05, Brian Mitchell <bina...@gmail.com> wrote:
> Hello fellow rubyists,
>
> What I have bellow is what started as a post to RedHanded. It was
> growing in size too rapidly so I decided to post here for all to see.
> Sorry for starting yet another thread on these topics. It is rough so
> please don't nit pick details. I don't want this to start a flame war
> (though I can't do much about that now). I would rather see some ideas
> on how to get the best of both worlds. Some of this won't come without
> a compromise so keep that in mind. I apologize in advance if I did
> make any grievous errors in my interpretations.
>
> There is a matter of taste involved but beyond that there are a few
> easy comparisons. I will try to keep this down to just that (though a
> few may be on a grey line, I hope they are clear enough).
>
> Let me cite Matz's slides first:
> * Make method calls more descriptive
> * Order free arguments
>
> With that simple goal in mind, lets start the comparisons.


>
> Sydney's argument scheme (s_ henceforth) is simple when you want to
> reorder the arguments.
>
> def s_f1(a,b,c) ... end
> s_f1(b:2, a:1, c:3)
>
> Matz's scheme (m_ from now on) allows this too:
>
> def m_f1(a:,b:,c:) ... end
> m_f1(b:2, a:1, c:3)
>

> Ok. Not much difference right away no clear winner. Lets examine


> another variation on calling these:
>
> s_f1(1,2,3) # Simple. current behavior.
> m_f1(1,2,3) # Error. No positional arguments.
>
> This shows one point that goes to s_. It makes it easy to use keyword
> args that still have position. However, Matz could consider to allow
> keyword arguments to count as positional arguments and make this
> example go away. It is up to him. +1 for s_ for now. The change would
> force non keyword args to come before keyword args. simple enough.
> Though I still don't see a good reason to share both positional and
> keyword arguments (a good example would be of great help in this
> discussion).
>
> The next example will be a method that takes any number of key-worded arguments:
>
> def m_f2(**keys) ... end
> m_f2(k1: 1, k2: 2, k3: 3)
>
> def s_f2(*args) ... end
> s_f2(k1: 1, k2: 2, k3: 2)
>
> That works but there are some complications that the s_ method starts
> to see (the hidden ugly head). *args now gets an array with hash

> (key-value) or a value with each entry. Ugly. Now something internal


> is depending on how someone on the outside (away from the interface)
> called it to see what it gets. I hope this is clear enough for you. +1
> for m_.
>

This was one part confusing me about s_. When we get our list it could
either be:

[1,2,3,4] or [{:k1 => 1, :k2 => 2, :k3 => 3}]

The problem is still there but in variation, the arguments might or
might not be in the hash. This blurring the line between the method
and the caller, which are currently two very separated things.
Checking this for an interface that handles not so simple calls might
be a burden more than an assistance. I will keep my conclusion between
the two.

Another problem brought to my attention by Matz's post is delegation.
One can not use this to delegate unless you keep you method interface
the same, this could be problematic over long chains of argument
passing (i.e. super could have unintended meaning now)

To clarify m_'s behavior I will copy some examples from Matz's slides
with some annotations:

def baz(*rest, a:4, b:0, **keys)
...
end

baz() # rest=[], a=4, b=0, keys={} <- notice that [] in args has an
implicit {} for **keys
baz(1) # rest=[1], a=4, b=0, keys={} <- explicit keys do not count as
positionals
baz(a:1) # rest=[{a:1}], a=1, b=0, keys={a:1} <- * will always contain
the full set of passed variables.
baz(a:1, b:2) # rest=[{a:1, b:2}], a=1, b=2, keys={a:1, b:2}
baz(1, 2, b:2) # rest=[1, 2, {b:2}], a=4, b=2, keys={b:2} <-
interesting. This result is for passing on correct values for
delegation.
baz(c:2) # rest=[{c:2}], a=4, b=0, keys={c:2} <- another one to think about.

> How about mixing positional and keyword args?
>
> def m_f3(p1, p2, k1:, k2:) ... end
> def s_f3(p1, p2, k1, k2) ... end
>
> *_f3(1,2,k1:3, k2: 4)
>
> Not much difference. m_ requires the extra : to be added. This is
> neither a plus or a minus as it can be easily argued both ways. No
> winner. (I will argue it if needed but trust me one can look both
> ways).
>
> How about having a variable number of positional arguments and a set
> number of keys?
>
> def m_f4(*args, a:, b:)
> m_f4(1,2,3,4,5,6,7,8, a:1, b:2) # misleading see bellow.
>
> def s_f4(a, b, *args)
> s_f4(1,2,3,4,5,6,7,8, a:1, b:2) # might have the same problem
>
> The s_ example is nice. It show an intuitive behavior at first but
> depending on implementation you can no longer pull a variable number
> of key paris or you have the same semantic problem that the m_ one

> has. If you use * at all that allows any number of arguments of any


> type to be passed. Assuming the latter behavior (needed for *args to
> work with delegation), then neither has any gain. I may be miss
> understanding s_ at this point so please point it out.
>

I will extend this with another way to explain it. *args means you can
also pass any number of keys also. This goes for both. This means
there is no way of having only variable numbers of positional
arguments and static numbers of keyword arguments.

m_f4(1,2,3, a:4, b:5, c:6) <- example of what I mean.

> How about having both keyword and positional arguments mixed in a
> catch-all with *?
>
> def m_f5(*args)
> m_f5(1,2, a:3, b:4)
>
> def s_f5(*args)
> s_f5(1,2 a:3, b:4)
>
> Well things start to contrast now. For s_ you get: [1,2, { :a => 3}, {
> :b => 4}] if I understand correctly. m_ gives you [1,2, {:a => 3, :b

> => 4}]. I won't debate on which is better in this case. Most of this


> is involved with opinion. However, if you want to look at positionals
> alone and keys alone it is easy with m_ we now have the hash collected
> at the end of *args and can use **keys if we want to. Not a huge plus
> but a point to make things easy. It will minimize boilerplate code on
> a method. I give m_ a +1, you may disregard it if you don't agree.
>

I was wrong on this one. Let me try again.

For s_ you get: [1,2, { :a => 3, :b => 4}] if I understand correctly.
m_ gives you [1,2, {:a => 3, :b => 4}]. They seem to yield the same
result but let me give a new the s_ example to show how they are
practically the same:

def s_f6(a, b, *args)

s_f6(0, 1, 3, b:2)

s_f6's *args would yield something like [3, {:b => 2}] in this case
(If I get Daniel's reply correctly). a = 0, b = 1

s_f6(1, 3, a:0, b:2)

This time *args would look like [1, 3, {:b => 2}]. a = 0, b = 1.

This is an example of where it doesn't break which is in contrast to
my original interpretation. It seems neither would win here after
further analysis. It is a matter of style for this example.

> Now think about the above before we move on. Keep in mind that it is
> not just another way to call a method but gives the method's interface
> a richer meaning (like Matz's slide said).
>

This method is much cleaner now:

> def self.s_create(kind, name, *args)
> pet = Pet.allocate
> pet.kind = kind
> pet.name = name

get = args.last

> case(kind)
> when :ham
> pet.weight = get[:weight]
> when :cat
> pet.color = get[:color]
> when :dog
> pet.color = get[:color]
> pet.breed = get[:breed]
> when :ruby
> pet.facets = get[:facets]


> else
> fail "Uknown kind of pet: #{kind}"
> end
> end

> end
>
> Pet.m1_create(:ham, "selfish_ham", weight:2.3)
> Pet.m2_create(kind: :cat, name: "cat43", color: :black)
> Pet.s_create(:dog, "singleton", color: :brown, breed: :mini_pincher)
> Pet.s_create(kind: :ruby, name: "JRuby", facets: 26)


>
> My s_ method is messy and could probably be cleaned up but it still
> serves a point. Savor the style for a bit. It might add more verbosity
> but I think it gives us some good side effects for the small price
> (IMHO again). I think some really good points can be made for both
> side but my _feeling_ is that Ruby doesn't need another halfway there
> feature (IMHO). Keyword arguments are serious things and should be
> treated as part of your interface (IMHO). I feel that the semantics of
> m_ are more clear than the at first simpler look of s_ (IMHO -- why
> not just automatically append these till the end of my message). It is
> a hard choice. We still have one more option that I know of, change
> nothing. Hashes seem to get the job done for most people already. I
> know I missed something so please add to this. If I made any errors
> please correct them. Just avoid and unproductive and personal attacks
> please.
>

I've updated quite a bit of the code and commentary to reflect things.
The last comparison is mostly equal however, it does show some
ambiguities with calling in the future for both methods:

def foo(*args) ... end

foo(1, 2, a:3, b:4)
foo(1, 2, {:a => 3, :b => 4})

*args gets the same array in both cases.

Now before Daniel goes off on me about behaviors and how it handles
things ;) ... lets me continue with more evolution happening in the
community:

Behaviors allow Sydney to implement a prototype to these types of
behaviors. However, since they are a separate change to the language I
will leave it to someone else to give an overview of what they do and
don't give use. The interesting part is where Evan is taking his
implementation.

Currently, using a basic array for *args can cause ambiguous calls.
This could be solved by attaching an empty hash at the end of args in
all cases or maybe only certain cases (though something more
dependable is likely to be less work for the human mind). This make it
feel like we are continuously trying to fix the wrong approach to
keyword arguments (I speak for myself only).

After speaking with Evan a little about his plans in more detail, he
discussed that he is considering using a new kind of object in place
of an Array for *. The new class (which I will call Arguments), would
still act like an array (* would still work for expansion into
delegated calls). However, one could now go:

def bar(*rest)
rest.keywords
... etc ... # I am sure we could come up with a suitable interface.
end

This is the exact kind of thing I thing we should be looking for. I
don't know how Matz would feel about it. In fact I still am not sure
myself as I haven't tried using it in examples yet. The point stands
that there might be a good compromise to make between s_ and m_. This
goes a long ways towards that IMO.

Evan says he will be working on an implementation of this for Sydney.
I look forward to testing it live rather than typing code into GMail.
Matz, are there any patches that implement your proposal yet? I would
love to test that out too. If not anyone volunteer? I know I would be
wasting my time trying as I am not that much of an internals wizard.

Thanks,
Brian.


Trans

unread,
Oct 21, 2005, 2:25:32 PM10/21/05
to
<quote author="Brian">

After speaking with Evan a little about his plans in more detail, he
discussed that he is considering using a new kind of object in place
of an Array for *. The new class (which I will call Arguments), would
still act like an array (* would still work for expansion into
delegated calls). However, one could now go:

def bar(*rest)
rest.keywords
... etc ... # I am sure we could come up with a suitable interface.
end

This is the exact kind of thing I thing we should be looking for.

</quote>

Ah, now that's a breath of fresh air. And very nice job of combining
new class with Array behavior for backward compatiblity. Intersting
approach. Please let us know how it proceeds.

T.

itsme213

unread,
Oct 21, 2005, 6:14:11 PM10/21/05
to
"Christophe Grandsire" <christophe...@free.fr> wrote in message

> Positional arguments are *not* part of
> the name of the function. Their position is part of its signature

Their number is part of the signature (rather than their position(s)).

> Keyword arguments, being just a
> part of the name of a method, must be explicitly marked as such
> by the developer, and shouldn't be allowed to be left out by the
> user, just like you can't leave out the name of a method.

I have always preferred this semantics.

It also means keyword argument names must be available through reflection.

Nikolai Weibull

unread,
Oct 21, 2005, 6:25:26 PM10/21/05
to
Berger, Daniel wrote:

I’m not pretending to understand what the whole discussion is about, but
as far as I understand, keyword arguments for Ruby as suggested by matz
are very much like those found in Common Lisp. I don’t see them having
a hard time using them. I think that the way keyword arguments are used
in Common Lisp makes a lot of sense. Give mandatory arguments as
positional arguments and then pass in any optional arguments as keyword
arguments in any order you see fit, e.g., the find function in Common
Lisp:

find-if predicate sequence &key from-end start end key => element

OK, the two first arguments are always going to be a predicate that we want
to test with, and a sequence we want to traverse. Then we have
optionaly keyword arguments that narrow the search, if we are so
inclined. I don’t see the point of naming every argument that we pass
around.

nikolai

--
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}


Christophe Grandsire

unread,
Oct 21, 2005, 9:32:09 PM10/21/05
to
En réponse à itsme213 :

>
> Their number is part of the signature (rather than their position(s)).
>

OK. That's about what I meant :) .

> > Keyword arguments, being just a
> > part of the name of a method, must be explicitly marked as such
> > by the developer, and shouldn't be allowed to be left out by the
> > user, just like you can't leave out the name of a method.
>
> I have always preferred this semantics.
>
> It also means keyword argument names must be available through reflection.
>

Indeed, very good remark.
--
Christophe Grandsire.

http://rainbow.conlang.free.fr

You need a straight mind to invent a twisted conlang.


Yukihiro Matsumoto

unread,
Oct 21, 2005, 11:12:05 PM10/21/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sat, 22 Oct 2005 00:44:58 +0900, Daniel Berger <Daniel...@qwest.com> writes:

|> def foo(*args)
|> # how do you delegate arguments?
|> bar(*args)
|> end
|>
|> def bar(a,b,c)
|> p [a,b,c]
|> end
|>
|> foo(1,a:2,c:3)
|
|Not allowed because redefinition of the same parameter raises an error. Here
|you're trying to define 'a' twice, once as the first positional argument, once
|as a named parameter.

Then what if foo(1,b:2,c:3) ?

|Yes, it's uglier. How does it work in your implementation? I'm curious to know
|how you preserve argument order.

For mine, args in foo becomes [1,{:a=>2,:c=>3}]. And suppose

def bar(a:,b:,c:)
p [a,b,c]
end

since it requires explicit keyword arguments, delegation should be
plain

bar(*args)

and bar prints [1,2,3].

|Let me ask you the same thing. What happens here with your implementation?
|
|class Foo
| def foo(a:, b:, c:)
| p [a,b,c]
| end
|end
|
|class Bar < Foo
| def foo(d:, e:, f:)
| super
| end
|end
|
|Bar.new.foo(f:3, e:2, d:1)

Bar#foo receives [{:f=>3,:e=>2,:d=>1}], then it delegates arguments to
Foo#foo. Foo#foo accepts keyword arguments a, b, c, and no other
keywords (it does not have ** in the list), it raises ArgumentError.

matz.


Yukihiro Matsumoto

unread,
Oct 21, 2005, 11:37:09 PM10/21/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sat, 22 Oct 2005 07:25:26 +0900, Nikolai Weibull <mailing-lis...@rawuncut.elitemail.org> writes:

|I’m not pretending to understand what the whole discussion is about, but
|as far as I understand, keyword arguments for Ruby as suggested by matz
|are very much like those found in Common Lisp.

Exactly. I was writing slides about keyword arguments with opening
the CLtL book aside.

matz.


Yukihiro Matsumoto

unread,
Oct 21, 2005, 11:39:35 PM10/21/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sat, 22 Oct 2005 03:08:19 +0900, Brian Mitchell <bina...@gmail.com> writes:

|Matz, are there any patches that implement your proposal yet?

Not yet. The behavior was fixed on a night before the keynote. It is
much easier to implement than one in Sydney though.

matz.


ES

unread,
Oct 22, 2005, 12:58:31 AM10/22/05
to

These may not be the best arguments. Two scenarios are possible:

1) foo is supposed to be a transparent proxy: the caller must take care
to call it correctly, like the proxied object/method expects.

2) foo is supposed to present a real interface: the programmer must
take care that the arguments it receives are properly mapped to bar.

In both cases, an error should be raised if keyword arguments are
passed in with nonexistent keywords.

> matz.

E

Christian Neukirchen

unread,
Oct 22, 2005, 7:42:17 AM10/22/05
to
Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

Certainly, more language designers should do this. :-)

> matz.
--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org


gga

unread,
Oct 22, 2005, 8:45:57 AM10/22/05
to

Yukihiro Matsumoto ha escrito:

One question. Why this complexity in syntax? Why the strange and
very confusing ':' as the syntax delimiter in both function definition
and, worse, parameter passing? Sorry, but this just feels so
complicated to me and seems more something thought with ruby's parser
in mind, not the user.

What's wrong with '=' and avoiding defining explicit parameters in the
parameter definition.

Compare everything that was proposed with python's simplicity and
elegance:

# this is something akin to ruby's: def f(*args)
def f2(a, b, c, *d):
print a, b, c, d

# and this is akin to ruby's: def f(arg={})
def f(a, b, c='xxx', **d):
print a, b, c, d

# ---------------

f(1,2,3) # => 1 2 3 {}
f(a=4, b=5, c=8) # => 4 5 8 {}
f(3, b=5, c=8) # => 3 5 8 {}
f(b=5, 3) # SyntaxError: non-keyword arg after keyword arg
f(1,2,3, x="hello") # => 1 2 3 {'x' : "hello"}
f(1,2) # => 1 2 xxx {}

f2(1,2, 3, "hello", "a", "c") # => 1 2 3 ( 'hello', 'a', 'c')


There's a lot of things I don't like in python, but how functions are
defined is definitively one of the strongest things in the language.
As you can see above, things are much simpler. No need to use any
special syntax for named parameters in the function definition and the
use of '=' is a heck of a lot more clear than : or =>. Both array and
hash syntaxes for extra parameters are also accounted for.

Trans

unread,
Oct 22, 2005, 9:25:34 AM10/22/05
to
> What's wrong with '=' and avoiding defining explicit parameters in the
> parameter definition.

But = can be used to do assignment at the moment of passing:

def foo(x)
x
end

a = nil

foo (a=1) #=> 1

a #=> 1

T.

Yukihiro Matsumoto

unread,
Oct 22, 2005, 9:33:48 AM10/22/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sat, 22 Oct 2005 21:47:05 +0900, "gga" <gga...@advancedsl.com.ar> writes:

|What's wrong with '=' and avoiding defining explicit parameters in the
|parameter definition.

Unlike Ruby, assignments are expression in Ruby. Besides that, I
don't think Python keyword arguments are simple and elegant, but YMMV.

matz.


Daniel Schierbeck

unread,
Oct 22, 2005, 9:47:01 AM10/22/05
to
Because the keys *are* symbols, and they have colons in front of them.


Cheers,
Daniel

Daniel Schierbeck

unread,
Oct 22, 2005, 9:49:52 AM10/22/05
to
Damphyr wrote:
> The :a syntax looks a lot like symbols ...

Erm, the keywords *are* symbols.

def foo(a: 1, b: 2, **keys)
puts keys[:a] # :a is a symbol!
end

Therefore i think it's more clear if we write the keys as symbols.

def foo(:a = 1, :b = 2, **keys)
puts keys[:a] # foo(:a) -> keys[:a]
end


Cheers,
Daniel

Trans

unread,
Oct 22, 2005, 9:52:46 AM10/22/05
to
> Because the keys *are* symbols, and they have colons in front of them.

But they're *not* symbols. They're local vars.

T.

Daniel Schierbeck

unread,
Oct 22, 2005, 10:09:45 AM10/22/05
to

def foo(a:, **keys)
puts keys[:a] # the key "a" is a symbol
end

I'd agree if the named arguments worked like positional ones, ie

def foo(a:)
puts a
end

But unless I've completely misunderstood what's been suggested here,
that's not the case.


Cheers,
Daniel

ts

unread,
Oct 22, 2005, 10:17:22 AM10/22/05
to
>>>>> "D" == Daniel Schierbeck <daniel.s...@gmail.com> writes:

D> def foo(a:)
D> puts a
D> end

Well, matz has given the reason

vgs% cmucl -quiet
* (defun foo (&key a) (list a))

FOO
* (foo :a 12)

(12)
* (quit)
vgs%

OK ?


Guy Decoux


ts

unread,
Oct 22, 2005, 10:52:30 AM10/22/05
to
>>>>> "D" == Daniel Schierbeck <daniel.s...@gmail.com> writes:

D> def foo(a:, **keys)
D> puts keys[:a] # the key "a" is a symbol
D> end

and to give you another example

vgs% cmucl -quiet
* (defun foo (&rest keys &key a &allow-other-keys)(list keys a))

FOO
* (foo :a 12)

((:A 12) 12)
* (foo :a 12 :b 24)

((:A 12 :B 24) 12)
* (quit)
vgs%


Guy Decoux


Yukihiro Matsumoto

unread,
Oct 22, 2005, 11:04:35 AM10/22/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sat, 22 Oct 2005 22:33:48 +0900, Yukihiro Matsumoto <ma...@ruby-lang.org> writes:

|Unlike Ruby,

I meant "unlike Python".

matz.


David A. Black

unread,
Oct 22, 2005, 3:40:57 PM10/22/05
to
Hi --

:a = 1 parses visually like assignment to a symbol, and therefore
looks bizarre.

Bill Guindon

unread,
Oct 22, 2005, 6:35:51 PM10/22/05
to
On 10/21/05, Berger, Daniel <Daniel...@qwest.com> wrote:
> > -----Original Message-----
> > From: Trans [mailto:tran...@gmail.com]
> > Sent: Friday, October 21, 2005 8:12 AM
> > To: ruby-talk ML
> > Subject: Re: A comparison by example of keyword argument styles

<snip>

> > If keywords integrate the interface too tightly
> > with the code, then why tie them to the interface? Also, I
> > imagine there many be many more keyword arguments then
> > ordered args, this will make for some very LONG constructors:
> >
> > def stadium( height:, seating_capacity:, location:, color:,
> > sports:, concessions:, extra_features:, indoor:, yadayadayada: )

<snip>

> I'm glad you brought this example up. What do you do when you have a
> ton of accessors in your class? I have just such a case with the Format
> class in the spreadsheet package, where you have "font_name",
> "font_size", "border_color", etc. About 30 accessors I think.
>
> The solution here is NOT keywords arguments (regardless of
> implementation), where you would end up with ridiculously long
> constructors, as you mentioned. It's the old "yield self if
> block_given?" trick:
>
> class Format
> attr_accessor :font_color, :font_size, :bold # ...
> def initialize
> yield self if block_given?
> end
> end
>
> format = Format.new do |f|
> f.font_color = "blue"
> f.font_size = 10
> f.bold = true
> ...
> end

Has any thought been given to defining the parameters and keywords
using something similar to attr_accessor? Seems that would reduce the
long constructor problem, and would be fairly developer friendly.

It's always seemed strange to me that the two formats differ, seems a
nuisance when you've built up either the attr_accessor list, or your
parameter list, and you have to hand massage one to the other.

class Format
attr_accessor :font_face, :font_color, :font_size, :bold, :italic
def initialize
parameters :font_face='arial'
keywords :font_color='black', :font_size, :bold=false, :italic=false
...
end
end

format = Format.new('verdana')
format = Format.new(font_size: 1, bold: true)
format = Format.new('verdana', italic: true, font_size: 10)

granted, functon calls and constructors could still get quite lengthy.

disclaimer: this is not a thought that I'm in love with, just one that
crossed my mind.

> Regards,
>
> Dan

[OT] many thanks to those who put together the conference, and the videos.

--
Bill Guindon (aka aGorilla)


gga

unread,
Oct 22, 2005, 8:32:17 PM10/22/05
to
Trans said:
> foo (a=1) #=> 1

Yes, I am aware of that. But can you actually point to me some library
code that actually uses this as a feature? I have most definitively
never seen any ruby code using that as of yet, and even then, I would
say that variable assignment within an expression is just something to
win the obfuscated code award, not a useful functionality.

Matz mentioned:


>Besides that, I don't think Python keyword arguments are simple and elegant, but YMMV.

Could you elaborate why you prefer the other syntax? I can give you my
reasons for strongly suggesting following python's syntax, instead of
what you proposed.

To me, python's approach is simpler because:
a) There is no need for re-definiing a lot of previously written code
with a new syntax. If you have already written a function like
def x(a,b,c)
with the python automatic naming syntax, it makes the code still
work both positionally (as before) and now as named parameters --
automatically. Using a new syntax like a: or whatever, forces you to
basically have to rewrite all previously written code to make it work
with named parameters. While certainly functions that have used hashes
to accomplish a similar approach will need to get updated (or those
that used non-sensical names for function parameters), there shouldn't
be the need to update all previously written functions that did not
suffer from this. By not using any new special symbols, you gain the
functionality in pretty much most already written functions -- all of
ruby library, for example. A big, big plus, in my opinion. For the
parser and interpreter, it does makes things harder, but that's more or
less as it should be -- complexity on the side of the interpreter, not
on the side of the user.

b) There is a symetry between default parameter values and passing new
values to parameters in functions. This makes the code easier to
comprehend and the language easier to learn. That is:
def function(a, b = 2, c = 3):
...
function( 1, b = 4, c = 5)

or (sans parenthesis)
function b = 4, c = 5

(Yes, I know that with the current use of = in ruby, the above
"function b = 4, c = 5" makes it impossible for the interpreter to
disambiguate, but assume dispatching of equality was not allowed within
functions -- as it isn't during a def definition, so that parsing the
above should be possible).

Compared to (if I understood the proposal correctly):
def function(a, b: = 2, c: = 3) # ugly
end

function( 1, b : 4, c : 5)
function b: 4, c: 5 # use of : looks nicer, but
see also point c for issues

In this proposed ruby syntax, colons are used as assignment in
one situation, while in another situation, it is equality that it is
used. Confusing.

c) ruby already uses the :x syntax to denote symbols and, in the
ruby1.9 head also for hash definitions with symbol keys. This presents
another big, big, big source of confusion.
There was already a mail in this thread that already showed the big
confusion this leads to, as someone used the symbol notation in the
function definition incorrectly. Also, compare the invokation issues:
function to = :london, from = :paris
to:
function to: :london, from: :paris

The first example can not lead to typos that the interpreter will
misinterpret.
However, the second example can lead to two very easy to make
typos:
function :to :london # oops, two symbols used, etc. probably
flagged as syntax error during parsing?
function to::london # oops, this can NOT flagged as syntax
error, but leads to a runtime error only. Bad.

True, with the appearance of named parameters, the use of symbols
in function invokations will probably be much less than what it is now,
but...

Anyway, my 2 cents on the issue.

Trans

unread,
Oct 22, 2005, 9:17:42 PM10/22/05
to

Bill Guindon wrote:

> It's always seemed strange to me that the two formats differ, seems a
> nuisance when you've built up either the attr_accessor list, or your
> parameter list, and you have to hand massage one to the other.
>
> class Format
> attr_accessor :font_face, :font_color, :font_size, :bold, :italic
> def initialize
> parameters :font_face='arial'
> keywords :font_color='black', :font_size, :bold=false, :italic=false
> ...
> end
> end
>
> format = Format.new('verdana')
> format = Format.new(font_size: 1, bold: true)
> format = Format.new('verdana', italic: true, font_size: 10)
>
> granted, functon calls and constructors could still get quite lengthy.

But you can mitigate that. Also there's no need for this on regular
parameters, they can remain pretty much the same, though something like
this might be nice default values. Anyway:

class Format
attr_accessor :font_face, :font_color, :font_size, :bold, :italic

def initialize(font_face='arial')
key :font_color=>'black'
key :font_size
key :bold=>false
key :italic=>false
...
end
end

or just

class Format
attr_accessor :font_face, :font_color, :font_size, :bold, :italic

def initialize(font_face='arial')
keys :font_size,
:font_color=>'black',
:bold=>false,
:italic=>false
...
end
end

Though I am not using the new named parameters for the #keys method
itself here. Even so this is kind of nice. It's kind of like the lisp
stuff too. And in a way it's like a "keywords block", in fact:

class Format

attr_accessor :font_face, :font_color, :font_size, :bold, :italic

def initialize(font_face='arial') keys :font_size,
:font_color=>'black',
:bold=>false,
:italic=>false
puts "keeps the keys out ot the paranthetical"
end

end

The only things is that means key/keys becomes a keyword (no pun
intended). At least I think it would. Well, in that case we could take
it a bit further and pull a page out of Alex' book -- it might be even
nicer to predefine these keys:

class Format

attr_accessor :font_face, :font_color, :font_size, :bold, :italic

initkeys = keys :font_size,
:font_color=>'black',
:bold=>false,
:italic=>false

def initialize( font_face='arial', *initkeys )
puts "keeps the keys out ot the paranthetical"
end

end

Then they be reusable. Could extend this to parameters in general too.

T.

gga

unread,
Oct 22, 2005, 10:29:43 PM10/22/05
to
> Sorry, but when I have positional arguments, I only want to have to worry about
> their position for the API, and when I have keyword arguments, I only want to
> have to worry about their names for the API. In your proposal I have to worry
> about both, for all arguments. You seem to think that your proposal adds the
> advantages of both styles. In my opinion it only adds together their drawbacks.
> The advantages of keyword arguments disappear when there's a chance that someone
> will call them positionally, and the advantages of positional arguments
> disappear when there's a chance that someone will use them with keywords.

Well, I just realized reading the thread again that, syntax differences
aside, Sydney's proposal of making all parameters be allowed to be
named parameters is very akin to that of Python, while Matz proposal is
very much like Common Lisp. Sorry for being a tad slow... I
understand Matz dislike for python's approach now. I completely agree
from theoretical pov.

Question, however, is from a practical pov. Since python has supported
a Sydney-like function definition since v2.0 (ie. for the past 3 years
or longer), has this issue come up and has been a clear problem for
developers of libraries in that language?

gga

unread,
Oct 22, 2005, 11:35:30 PM10/22/05
to
> Could you elaborate why you prefer the other syntax? I can give you my
> reasons for strongly suggesting following python's syntax, instead of
> what you proposed.

Never mind me. I read David Black's response and I see the point.

Still, if the positional / named argument definition is chosen, could I
also suggest that a symbol (or keyword) is used to delimit positional
vs. named arguments, without having to specify it on each variable?

That is, instead of:

def function( a, b, c, d:, e: = 1, f: )
end

Something along the lines of:

def function( a, b, c : d, e = 1, f )
end

where parameters to the left of the colon (or whatever symbol/keyword
you choose) are positional parameters and those to the right are named
ones. A more readable symbol for this would be "!" or "|" but
obviously these conflict with ruby's use of those for negation/or.
This would somewhat help solve the issue of the definition being so
easily confused with symbols, make the function more readable (imo) and
would lead to less typing, too. If your model is CLISP, this is also
how CLISP deals with this (using &key), like:

(defun foo ( &key a b c ) (list a b c))

Thanks... sorry for my 3 emails.

gabriele renzi

unread,
Oct 23, 2005, 6:34:59 AM10/23/05
to
gga ha scritto:


> Question, however, is from a practical pov. Since python has supported
> a Sydney-like function definition since v2.0 (ie. for the past 3 years
> or longer), has this issue come up and has been a clear problem for
> developers of libraries in that language?
>

AFAIK, no, some pythonic friends seem to agree with this.
I still don't understand what the CLish proposal adds over a pythonic
one (sydney's one + **kw. I do like **kw split from *args).

The only two things that I understand as problematic are
- c API
- some fuzzy sense of danger ("he's seeing my arguments' name!")

OTOH it is much more complex, IMHO

gabriele renzi

unread,
Oct 23, 2005, 7:40:07 AM10/23/05
to
David A. Black ha scritto:

>> The separation between implementation and behavior you make here is lost
>> the moment you commit to supporting a keyword argument for any given
>> method, regardless of the fact that it was an explicit, conscious
>> choice. Once chosen, you're still beholden to that keyword name forever
>> unless you want to break backwards compatability. I think the perceived
>> freedom is an illusion.
>
>

> But that's the point: keyword arguments represent a decision to name
> your arguments. It's just like a hash. If I say that my method takes
> a hash:
>
> :first_name => ..., :last_name => ...
>
> then of course I've committed to those keys, and can't change them
> whenever I feel like it.

My 2c, some side view to add to this multifaceted debate:
I think you're supposing people will use your keyword arguments, which
is in many cases unrealistic.
It does not matter what the names are if an user would use them only
when they make sense (i.e. I won't call p(obj: foo) )

OTOH whenever you expect people to use your arguments by name (i.e.
:rails =>stuff) you would commit anyway to keyword arguments even with
the dual-scheme. Do you think otherwise?

> I just don't see why it has to be a winner-take-all situation, when
> it's perfectly possible to have both keywords arguments and
> "uncoupled" positional arguments.

because it is much simpler, and it avoid the need for an author to
choose beetween two different schemes.


>> There seems to be this fear of using an argument name, and then later
>> changing your mind about what the argument name should be called.
>
>

> It's not a fear: it's a right :-) Having local variable names always
> be part of the API just doesn't make sense to me at all.

I think they are already part of an api, since they are documentation.
They may not be strictly enforced but you're still not expected to
change them since
Time.new(duration)
is meaningful to people reading the api.

>> To that I reply that, even with the explicit syntax, this issue does
>> not go away. I would also say that all the implicit syntax does is
>> force you to think more up front about your API and naming
>> conventions. With Sydney, at least you can resort to positional
>> parameters in the unlikely event that the argument name did change,
>> something you can't do with Matz's current proposal afaik.
>
>

> But that means the caller has to keep track of whether or not the
> maintainer of the code has change variable names. I don't want to be
> on either end of that. It could be a refactoring and/or maintenance
> nightmare.

I also heard you can't have a reliable application written in dynamic
languages, since they can be a refactoring and/or maintenance nightmare,
the fact is that this is wrong ;)

Python people have been using a merged-named-and-positional scheme for
some years and it never shown itself as a problem (actually, I think it
helps refactoring tools based on heuristics).

There could be other problems (i.e. the c api) with this scheme, but I
think this kind of fear is unmotivated

Yukihiro Matsumoto

unread,
Oct 23, 2005, 8:32:30 AM10/23/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"


on Sun, 23 Oct 2005 12:37:00 +0900, "gga" <gga...@advancedsl.com.ar> writes:

|That is, instead of:
|
| def function( a, b, c, d:, e: = 1, f: )
| end

Right syntax is

def function(a, b, c, d:, e: 1, f:)
end

|Something along the lines of:
|
| def function( a, b, c : d, e = 1, f )
| end
|
|where parameters to the left of the colon (or whatever symbol/keyword
|you choose) are positional parameters and those to the right are named
|ones.

|If your model is CLISP, this is also


|how CLISP deals with this (using &key), like:
|
| (defun foo ( &key a b c ) (list a b c))

I considered that idea too, but I chose similarity to calling
syntax.

matz.


Yukihiro Matsumoto

unread,
Oct 23, 2005, 8:44:16 AM10/23/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sun, 23 Oct 2005 11:32:00 +0900, "gga" <gga...@advancedsl.com.ar> writes:

|Question, however, is from a practical pov. Since python has supported
|a Sydney-like function definition since v2.0 (ie. for the past 3 years
|or longer), has this issue come up and has been a clear problem for
|developers of libraries in that language?

I think Sydney-like function definition would not cause big problems.
But if I had to choose between Lisp and Python, I'd always choose the
former.

matz.


Trans

unread,
Oct 23, 2005, 9:26:14 AM10/23/05
to
List is great but I don't program in Lisp because of my eyes become
crossed in looking at it. I don't what the same thing in Ruby.

def foo( c: ) # looks bad

foo( c: :many ) # horrible!!!

I don't understand why this is acceptable. Symbols are common
arguments. Space significance is poo-poo'd everywhere else. If this is
allowed, why not

class X
def {}(x)
end
end

X.new{1}

A _space_ can distinguish block:

X.new {1}

To me it smacks of same thing. Worse, 'c::many' has whole other
meaning.

This is terrible. Why do you not care about this Matz? Why do so many
not seem to care about this?

T.

Yukihiro Matsumoto

unread,
Oct 23, 2005, 10:06:13 AM10/23/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Sun, 23 Oct 2005 22:27:04 +0900, "Trans" <tran...@gmail.com> writes:

|List is great but I don't program in Lisp because of my eyes become
|crossed in looking at it. I don't what the same thing in Ruby.
|
| def foo( c: ) # looks bad
|
| foo( c: :many ) # horrible!!!

It might be horrible, but it's at least different story from Lisp
ugliness.

|This is terrible. Why do you not care about this Matz? Why do so many
|not seem to care about this?

Just because it's better than other proposals. Even if there can be a
perfect solution, I haven't seen one yet.

matz.


nobu....@softhome.net

unread,
Oct 23, 2005, 10:15:23 AM10/23/05
to
Hi,

At Sun, 23 Oct 2005 21:32:30 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:162119]:


> |Something along the lines of:
> |
> | def function( a, b, c : d, e = 1, f )
> | end
> |
> |where parameters to the left of the colon (or whatever symbol/keyword
> |you choose) are positional parameters and those to the right are named
> |ones.
>
> |If your model is CLISP, this is also
> |how CLISP deals with this (using &key), like:
> |
> | (defun foo ( &key a b c ) (list a b c))
>
> I considered that idea too, but I chose similarity to calling
> syntax.

What about semicolon like as block parameters.

def function(a, b, c = ""; d, e = 1, *f)
end

--
Nobu Nakada


Eric Mahurin

unread,
Oct 23, 2005, 10:37:37 AM10/23/05
to
--- nobu....@softhome.net wrote:

At first glance I like this, but ...

- with only keyword args, it looks a little ugly:
def function(; d, e = 1, *f)

- in 1.9, ";" is already used as a delimiter (in the argument
list) for block local variables. I assume keyword args will be
allowed with blocks/lambdas.

Just for reference, another language that takes "keyword"
arguments is verilog (hardware language). It is ugly, but it
looks like this:

foo ( .a(1), .b(2), .c(3) ) # order doesn't matter
foo ( 1, 2, 3 ) # a=1, b=2, c=3




__________________________________
Yahoo! Mail - PC Magazine Editors' Choice 2005
http://mail.yahoo.com


Daniel Berger

unread,
Oct 23, 2005, 10:54:10 AM10/23/05
to
Trans wrote:
> List is great but I don't program in Lisp because of my eyes become
> crossed in looking at it. I don't what the same thing in Ruby.
>
> def foo( c: ) # looks bad
>
> foo( c: :many ) # horrible!!!
>
> I don't understand why this is acceptable. Symbols are common
> arguments. Space significance is poo-poo'd everywhere else.

I could live with this particular exception. Seriously, what are our
alternatives for keyword syntax in method calls?

"foo(x: 1)"
Pros: Probably easiest to parse. Familiar to Smalltalkers and Lispers.
Cons: Symbols force space, look ugly.
Aside: I don't expect to see a lot of folks passing symbols to keywords
arguments in practice.

"foo(x => 1)"
Pros: Familiar syntax, fairly intuitive.
Cons: More verbose, difficult (impossible?) to distinguish from a Hash.

"foo(x = 1)"
Pros: Clean, simple, intutive. Familiar to Pythonistas.
Cons: May very well be impossible to implement because '=' is an
expression.

"foo(x := 1)"
Pros: Avoids the SSW issue with symbols.
Cons: Unfamiliar syntax, smells like Ada.

If Evan can, by some wizardry, get '=' to work in Sydney, that is the
proposed syntax I would favor. Otherwise, I can certainly live with
":" and a forced whitespace for symbols.

> This is terrible. Why do you not care about this Matz? Why do so many
> not seem to care about this?

He does care. That's why he's joined this discussion in public, and
probably has some interest in seeing how Sydney does things.

Regards,

Dan

Trans

unread,
Oct 23, 2005, 11:06:42 AM10/23/05
to
> He does care. That's why he's joined this discussion in public, and
> probably has some interest in seeing how Sydney does things.

Point taken, though I didn't mean it like THAT, but that he didn't
address it when brought up in earlier posts.

I hate to say, but it seems like the selection of a character commonly
used for assignment operations, i.e. ':' as a prefix for symbols has
come back to haunt. Go back in time Matz! Throw out the '=>', use ':'
instead, and chose us another symbol symbol!

T.

Nikolai Weibull

unread,
Oct 23, 2005, 11:15:51 AM10/23/05
to
Trans wrote:

> List is great but I don't program in Lisp because of my eyes become
> crossed in looking at it. I don't what the same thing in Ruby.
>
> def foo( c: ) # looks bad
>
> foo( c: :many ) # horrible!!!

Since you write “foo( c: :many )” I don’t understand why you are worried
about not being able to remove the space between symbols and the keyword
argument. You obviously like your whitespace in abundance as you put in
the horribly looking spaces after and before opening and closing
parentheses.

nikolai

--
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}


Trans

unread,
Oct 23, 2005, 11:29:30 AM10/23/05
to

Nikolai Weibull wrote:
> Trans wrote:
>
> > List is great but I don't program in Lisp because of my eyes become
> > crossed in looking at it. I don't what the same thing in Ruby.
> >
> > def foo( c: ) # looks bad
> >
> > foo( c: :many ) # horrible!!!
>
> Since you write "foo( c: :many )" I don't understand why you are worried
> about not being able to remove the space between symbols and the keyword
> argument. You obviously like your whitespace in abundance as you put in
> the horribly looking spaces after and before opening and closing
> parentheses.

Hey, blame _why I picked up the habbit from him :)

Even so, its a preference not a neccessity, and to me it helps
readability. c: :many does not.

T.

Yukihiro Matsumoto

unread,
Oct 23, 2005, 11:46:33 AM10/23/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Mon, 24 Oct 2005 00:07:01 +0900, "Trans" <tran...@gmail.com> writes:

|I hate to say, but it seems like the selection of a character commonly
|used for assignment operations, i.e. ':' as a prefix for symbols has
|come back to haunt. Go back in time Matz! Throw out the '=>', use ':'
|instead, and chose us another symbol symbol!

For example? It that good enough to break thousands of lines of code?

matz.


Warren Seltzer

unread,
Oct 23, 2005, 12:10:21 PM10/23/05
to
See also what some other languages have done:
http://www.google.com/search?hs=IOh&hl=en&rls=org.mozilla%3Aen-US%3Aofficial&q=keyword+pos
itional+arguments+rationale&btnG=Search

Warren Seltzer

Trans

unread,
Oct 23, 2005, 12:14:18 PM10/23/05
to

Not if you go back in time it won't ;)

Might have used backtick `abc, kind of like Lisp 'literal, or maybe
backticks `abc`. Leading underscore _abc might have worked well too.
But as you say, that's a lot of code breaking --that would be a major
shift.

T.

P.S. If you're keeping ':' might you deprecate '::'? That'd help.

Warren Seltzer

unread,
Oct 23, 2005, 12:31:48 PM10/23/05
to
Keyword args will make several things harder:
Inheritance
Reflection
Tools that parse
Linking
Dynamic Linking

A future version of compiled Ruby might want to:

LibraryPath = [...]
somefunc(a=5, z=9) ## Go find the function "somefunc" on the library path (with
keyarg a and z) , arrange the args, and call it.

After all, they compile lisp, don't they?

With plain old non-dynamic linking, you'd have to generate the code to call 'somefunc'
before you saw it. Will we have include files?


Warren Seltzer

David A. Black

unread,
Oct 23, 2005, 2:10:48 PM10/23/05
to
Hi --

No. Nor is there any reason for Ruby to converge onto what's common
in other languages. : for symbols is fine.

Daniel Schierbeck

unread,
Oct 23, 2005, 2:15:42 PM10/23/05
to
This is just to get the discussion focused. With named arguments, I'm
thinking something along the line of this:

An assignment symbol of some sort ("=", ":", "=>", "->", etc.), with a
key on the left side and a value on the right side.

key: value
key = value
:key = value
key => value
key -> value

Furthermore, the named arguments are gathered in a hash in which the
keys are symbols.

keys[:key] -> value

We're discussing two things: what assignment symbol to use and what the
key should look like (although the latter doesn't seem to be causing
much trouble). I'll just go through each of the styles suggested above
and pose my thoughts on them.


key -> value

def foo(a -> "default", **keys)
foo(a -> "foobar")

con: I don't think we want to add another arrow to the language.
No way to specify a named argument without a default value.


key => value

def foo(a => "default", **keys)
foo(a => "foobar")

pro: It's what being used at the caller-level already. It looks cool,
even when the value's a symbol: foo(a => :b).

con: To me, => means "points to", not "is". Therefore it might not be
good as an assignment symbol. No way to specify a named argument
without a default value.


key: value

def foo(a:, b: "default", **keys)
foo(a: "foobar")

pro: Already used in other languages. Intuitive in many cases:
obj.move from: NewYork, to: Paris

con: Looks silly when the value is a symbol:
obj.move from: :newyork, to: :paris
mandatory named arguments look silly.


:key = value

def foo(:a, :b = "default", **keys)
foo(:a = "foobar")

pro: The key is a symbol, which seems consistent with it being it also
in the key hash. Looks cool even when the value is a symbol.

con: Looks like you're assigning a value to a symbol.


key = value

foo(a = "foobar")

pro: Looks clean and cool, even when the value is a symbol.

con: May be hard to implement. Doesn't specify how you seperate named
and positional arguments (maybe use a keyword like "named"?).
def foo(a, b = "bar", named c = "default", **keys)


Personally I prefer the last version (key = value) with a keyword in
front of named arguments. Furthermore, the key: value syntax could be
used alongside, where appropriate, on the caller side.

def foo(a, b = "bar", named c, named d = "default", **keys)
foo(1, "foo", c = 123)
foo(1, "foo", c: 123)

Just my $.02

Cheers,
Daniel

Trans

unread,
Oct 23, 2005, 2:52:17 PM10/23/05
to

Daniel Schierbeck wrote:
> key => value
>
> def foo(a => "default", **keys)
> foo(a => "foobar")
>
> pro: It's what being used at the caller-level already. It looks cool,
> even when the value's a symbol: foo(a => :b).
>
> con: To me, => means "points to", not "is". Therefore it might not be
> good as an assignment symbol. No way to specify a named argument
> without a default value.

There's no reason you can't leave the value off.

def foo(a=>) # same as foo(a=>nil)

I'm not saying its great. But it would work. And the pros for this are
pretty signifficant.

The 'key: :sym' effect is very unfortunate. I use symbol argument in a
number of places. Whether I will use them with keys much, who knows,
but given the problem I probably just won't and may even end up only
using => so as to avoid it. Then the ':' may as well not exist. I don't
know. But it sure would be nice if there was a simple fix to this.
Perhaps if backticks can become an *additional* way to express a
symbol? I know they are currently used for a type of system call, but
I'm sure a regular method would be okay for that. And I don't think
that's too much to ask of Ruby 2.0. Seems like a reasonble solution.

Of course there's still the question of Evan vs. Matz keyword
arguments. I can go either way. I think we all pretty much can go
either way. We know one works fine for Python, we know the other works
fine for Lisp. Is one truly better than the other? Doesn't seem like it
--at least not by much. Mostly, they're just different. Pick one.

T.

Nikolai Weibull

unread,
Oct 23, 2005, 3:45:34 PM10/23/05
to
Daniel Schierbeck wrote:

> key = value
>
> foo(a = "foobar")
>
> pro: Looks clean and cool, even when the value is a symbol.
>
> con: May be hard to implement. Doesn't specify how you seperate named
> and positional arguments (maybe use a keyword like "named"?).
> def foo(a, b = "bar", named c = "default", **keys)

It’s impossible to implement without breaking the current semantics of
the assignment operator.

To me, “a = "foobar"” reads very much like an assignment, not as an
argument specifier, but one mans opinion is more or less irrelevant.

If everyone can just get around the fact that passing symbols using
keyword arguments will look a bit awkward, with the two colons in a row
separated by a space, I really don’t see what the problem is. For every
other case, I think that <symbol>':'<ws>+<expr> reads a lot better than
<symbol><ws>*'='<ws>*<expr>, or


ary.grep(/regex/, start: 5, end: 8)

over


ary.grep(/regex/, start = 5, end = 8)

Reading the latter, I find my brain wondering where start and end are
being used in the code preceding and following the call to
Enumerable#grep. In the earlier I don’t get the feeling that “start”
and “end” are variables that are getting values assigned to them.

Ryan Leavengood

unread,
Oct 23, 2005, 3:53:41 PM10/23/05
to
On 10/23/05, Nikolai Weibull

<mailing-lis...@rawuncut.elitemail.org> wrote:
> ⋮
> ary.grep(/regex/, start: 5, end: 8)
> ⋮
>
> over
>
> ⋮
> ary.grep(/regex/, start = 5, end = 8)
> ⋮
>
> Reading the latter, I find my brain wondering where start and end are
> being used in the code preceding and following the call to
> Enumerable#grep. In the earlier I don't get the feeling that "start"
> and "end" are variables that are getting values assigned to them.

I agree. At least both the Sydney and Matz techniques for keyword
arguments use the colon. I do not think using equals will ever be a
valid option. Ruby isn't Python, and thank goodness for that.

Ryan

Nikolai Weibull

unread,
Oct 23, 2005, 4:08:42 PM10/23/05
to
Trans wrote:

> The 'key: :sym' effect is very unfortunate. I use symbol argument in a
> number of places.

Yes, it’s a bit ugly, but to me, using => for key-value pairs is not
visually pleasing either. However, I use them all the time when
creating hashes. How about ‘⇒’?

> Whether I will use them with keys much, who knows, but given the
> problem I probably just won't and may even end up only using => so as
> to avoid it. Then the ':' may as well not exist.

What, we shouldn’t have ‘:’ since you personally will never use it?

If you don’t know how you will be using keyword arguments, then how can
you know if the proposed syntax will cause a visually displeasing
result? As I said in my other mail on this sub-thread, I think that
we’re making too much of the “but symbol arguments to keyword parameters
will look ugly” issue.

> I don't know. But it sure would be nice if there was a simple fix to
> this. Perhaps if backticks can become an *additional* way to express
> a symbol? I know they are currently used for a type of system call,
> but I'm sure a regular method would be okay for that. And I don't
> think that's too much to ask of Ruby 2.0. Seems like a reasonble
> solution.

How about "symbol".to_sym? Personally, I’d love to see Unicode being
used in Ruby’s syntax (OK, I know that it won’t happen, but as long as
we’re on this rather pointless discussion):

• «symbol»
• »symbol«
• »symbol
• ⟨symbol⟩

> Of course there's still the question of Evan vs. Matz keyword
> arguments.

Named arguments versus keyword arguments, to be more precise, as they
are two different things. Or have I missed something?

> I can go either way. I think we all pretty much can go either way. We
> know one works fine for Python, we know the other works fine for Lisp.
> Is one truly better than the other? Doesn't seem like it --at least
> not by much. Mostly, they're just different. Pick one.

They are two different things. Keyword arguments are a cleaner way to
implement methods that take optional parameters. Instead of writing a
method like

def m(a, b, c = 1)

end

we can write it as

def m(a, b, c: 1)

end

and then at invocation we write

m(1, 2, c: 3)

instead of

m(1, 2, 3)

to make it clear that we are passing an argument to a parameter that is
usually optional.

Named arguments is just a way of naming the parameter to tie the given
argument to.

They seem to be the same thing, but in reality they aren’t. Personally,
I don’t see the point of naming arguments, as parameters are usually
ordered in a sensible way already (i.e., travel(from, to) is clear
enough; travel(from: from, to: to) doesn’t add anything). I do,
however, see a point of being able to clearly state what optional
(keyword) parameters I do care about, as this allows me to skip defining
those that I don’t care about:

def m(a, b, c: 1, d: 2)

end

m(1, 2, d: 4)

Eric Mahurin

unread,
Oct 23, 2005, 4:50:39 PM10/23/05
to
--- Daniel Schierbeck <daniel.s...@gmail.com> wrote:

> Furthermore, the named arguments are gathered in a hash in
> which the
> keys are symbols.
>
> keys[:key] -> value

I don't think this should be an assumption about how named
arguments work (unless you are talking about the final **keys
arg). The easiest initial implementation may be to use hashes
to pass around named arguments, but as we get better VM's and
compilers, that could change.

The main thing I don't like about the current proposal (what
matz presented at rubyconf) is that the *args (remaining
positional args) also contains the named arguments. So this:

def foo(a,b=1,*args,c:,d:2,**keys) ... end

called like this:

foo("a","b","x","y",c:"c",e:"e")

gives:

a = "a"
b = "b"
args = ["x","y",{ :c => "c", :d => 2, :e => "e" }]
c = "c"
d = 2
keys = { :e => "e" }

What use is it to have the named arguments appear twice? I
understand the need if you don't have named arguments in the
definition (compatibility), but as soon as named arguments are
specified, it seems to serve no purpose.

Also, like we have array splatting when you call a method, I
think hash splatting would also be useful. matz said that
hashes would be automatically splatted if they were the last
argument, but this results in ambiguity:

def foo(a,b={},c:2,**keys) ... end

foo("a",{:x => 1,:y => 2})

Does the above result in:

a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}

or:

a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}

I would rather see it be the first interpretation and if you
wanted the second, you'd "splat" the hash:

foo("a",**{:x => 1,:y => 2})

which would be the same as:

foo("a", x : 1, y : 2)


I think whether we have something sydney/python like where
positional arguments can automatically be named or whether
there is a clear distinction between positional/named like
lisp, it is OK. Another language comparison to make is just
the shell command-line. One the command-line named arguments
are effectively the "options" and positional are the rest. On
that note, another option would be to specify the named
arguments like command-line options:

def foo(a, b=1, --c=2, --*keys) ... end

foo("a", --c="c", --x=1, --y=2)

Or simply "-" instead of "--" if it could be handled in the
parser (could be confused with a unary - at first). But, I'm
not terribly concerned with syntax.

I'm hoping that we have enough reflection for these named
arguments like #arity. I'm thinking that with named arguments
a potential simple application would be as a spec for handling
command-line options (named arguments). I'd like to see all of
the keywords and defaults accessible from Proc/Method objects.
It'd be nice to have access to defaults of positional args
while wer'e asking.

Since Ruby 2 will also be completely redoing how
multiple-values are handled, why not also consider being able
to name your return values? If a method returns a bunch of
attributes, it would be nice for the caller to be able to pick
what they want.

Toby DiPasquale

unread,
Oct 23, 2005, 6:41:31 PM10/23/05
to
On Sun, Oct 23, 2005 at 11:57:49PM +0900, Daniel Berger wrote:
> I could live with this particular exception. Seriously, what are our
> alternatives for keyword syntax in method calls?
>
> "foo(x: 1)"
> Pros: Probably easiest to parse. Familiar to Smalltalkers and Lispers.
> Cons: Symbols force space, look ugly.
> Aside: I don't expect to see a lot of folks passing symbols to keywords
> arguments in practice.

For my part, I prefer this syntax. Its natural to Lisp programmers,
relives much of the parsing burden on the core code and is easy to
understand for people who haven't ever used Lisp. I can't see what's so
ugly about this syntax and I don't find much sense in Trans' arguments. As
for Sydney's syntax, it too is nice, but I would prefer the syntax that
can be parsed the fastest; Ruby doesn't need to get any slower before
YARV integration. I already have to write C extensions to do some stuff at
reasonable speeds, exactly the thing I got into Ruby to avoid ;-)

--
Toby DiPasquale


Yukihiro Matsumoto

unread,
Oct 23, 2005, 7:34:53 PM10/23/05
to
Hi,

In message "Re: A comparison by example of keyword argument styles"

on Mon, 24 Oct 2005 05:50:39 +0900, Eric Mahurin <eric_m...@yahoo.com> writes:

|What use is it to have the named arguments appear twice? I
|understand the need if you don't have named arguments in the
|definition (compatibility), but as soon as named arguments are
|specified, it seems to serve no purpose.

It's for method delegation. Currently we do

def foo(*args)
bar(*args)
end

for method delegation. Under my proposal, this delegation would still
work fine, since we have named arguments appear twice, otherwise we
must change the code as

def foo(*args, **keys)
bar(*args, **keys)
end

everywhere, to just do delegation.

|Also, like we have array splatting when you call a method, I
|think hash splatting would also be useful. matz said that
|hashes would be automatically splatted if they were the last
|argument, but this results in ambiguity:
|
|def foo(a,b={},c:2,**keys) ... end
|
|foo("a",{:x => 1,:y => 2})
|
|Does the above result in:
|
|a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}
|
|or:
|
|a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}

The former. Keyword argument uses the last remaining hash.

|I'm hoping that we have enough reflection for these named
|arguments like #arity. I'm thinking that with named arguments
|a potential simple application would be as a spec for handling
|command-line options (named arguments). I'd like to see all of
|the keywords and defaults accessible from Proc/Method objects.
|It'd be nice to have access to defaults of positional args
|while wer'e asking.

Accepting keywords should be obtained from some kind of reflection
API, although the API is not fixed yet. But I'm not sure default
values can be accessed since they are arbitrary expression, and we
have no good way to represent pre-evaluated expression in Ruby (unlike
in Lisp, where we can use S expression).

|Since Ruby 2 will also be completely redoing how
|multiple-values are handled, why not also consider being able
|to name your return values? If a method returns a bunch of
|attributes, it would be nice for the caller to be able to pick
|what they want.

I have no good idea of multiple value binding for named values
(i.e. syntax). Do you?

matz.


Trans

unread,
Oct 23, 2005, 9:43:18 PM10/23/05
to
Yukihiro Matsumoto wrote:
> It's for method delegation. Currently we do
>
> def foo(*args)
> bar(*args)
> end
>
> for method delegation. Under my proposal, this delegation would still
> work fine, since we have named arguments appear twice, otherwise we
> must change the code as
>
> def foo(*args, **keys)
> bar(*args, **keys)
> end
>
> everywhere, to just do delegation.

This is sinking worse and worse into a stenchy quagmire. If someone
puts **keys in the parameters then it makes sense for the keys NOT to
appear in args. I know you want to remain backward compatable so
without **keys then the keys will appear in args. But how does one say
they want any number of ordered parameters but NO named parameters? I
suppose you just can't. Moreover the args won't be cleanly separated.
So this doesn't do us much good, I'll still be pop'n off trailing
hashes :( Really, think about that!

---

Thinking about reusing named parameters vs. adding key arguments
(better?) I recant on my previous statement of their being little
difference. The later does have one clear disadvantage: it requires a
choice --which parameters will be fixed and which will be keyed. Since
you can't have it both ways, it's really going to tie you down.
Consider this scenario:

You have a method already

def foo(a,b=1,c=2)

Now it's been a bother b/c you want to sometimes call it as foo(a,c).
But you can't. To get around, you've done what we've all done at one
point or another, created an extra method

def foo2(a,c=2,b=1)

Now along comes matz' keyd args. Does it help? Can you deprecate foo2
which you never really wanted in the first place and use?

def foo(a,b:1,c:2)

You can but, ugh, that's serious backward compatabilty breakage!!! So
what to do? Do you add YAM (yet another method) #foo3 for this? Do you
get tricky with it and do

def foo(a,b=1,c=2,b2:1,c2:2)
b = b || b2
c = c || c2

Well a little better, but now you have TWO DIFFERENT names for each
parameter and you could have just as well done this with a trailing
hash. The keyed args didn't buy you much of anything. Nope, it just
doesn't do us much good.

Buy let's say instead, here comes along the named parameters approach
like Sydney's. What happens? Easy peasy. Deprecate #foo2 (add a
warning) and your done. You can start using #foo in the new way
'foo(a,c:x)' as it suits you and backward compatability is maintained.

---

In anycase case one of the nice things about named args, should you
with to change a parameter name, you can offer both during a transition
period, in fact you may want to offer a few alternatives anyway to make
usage a bit more fluid.

def foo( beer:, beers:, beer_bottles: )
b = beer || beers || beer_bottles

A way to specify an OR in the signiture would be nice with something
like this too. Say:

def foo( beer: | beers: | beer_bottles: )
b = beer # doesn't matter which.

But again the problem that starts to arise here are _very large
signitures_. And again to me this indicatates a real need for some type
of Signture class one can use to define them and plug them in where
needed, even reuse them. Such an object would give ultimate reflexion
too.

---

Just some comparisions:

foo(:foo=>:do, :bar=>:re, :baz=>:mi) # today


foo(foo=>:do, bar=>:re, baz=>:mi) # minor adj.


foo(foo: :do, bar: :re, baz: :mi) # colon notation


foo(foo:`do, bar:`re, baz:`mi) # alt. symbol

---

BTW, those of you who do get me --I'm not trying to make some major
coherent argument. I'm just pointing out various vantages.

T.

Ara.T.Howard

unread,
Oct 23, 2005, 10:08:20 PM10/23/05
to
On Mon, 24 Oct 2005, Trans wrote:

> Yukihiro Matsumoto wrote:
>> It's for method delegation. Currently we do
>>
>> def foo(*args)
>> bar(*args)
>> end
>>
>> for method delegation. Under my proposal, this delegation would still
>> work fine, since we have named arguments appear twice, otherwise we
>> must change the code as
>>
>> def foo(*args, **keys)
>> bar(*args, **keys)
>> end
>>
>> everywhere, to just do delegation.
>
> This is sinking worse and worse into a stenchy quagmire. If someone puts
> **keys in the parameters then it makes sense for the keys NOT to appear in
> args. I know you want to remain backward compatable so without **keys then
> the keys will appear in args. But how does one say they want any number of
> ordered parameters but NO named parameters? I suppose you just can't.
> Moreover the args won't be cleanly separated. So this doesn't do us much
> good, I'll still be pop'n off trailing hashes :( Really, think about that!

it's not that big a deal to do is it? i've abstracted this in alib like so:

harp:~ > cat a.rb
require 'alib'
include ALib::Util

def meth *argv
args, opts = optfilter argv
foo = getopt 'foo', opts
bar = getopt 'bar', opts, 'forty-two' # default value

p 'args' => args
p 'opts' => opts
p 'foo' => foo
p 'bar' => bar
end

meth 'foo', 'bar', 'foo' => 42


harp:~ > ruby a.rb
{"args"=>["foo", "bar"]}
{"opts"=>{"foo"=>42}}
{"foo"=>42}
{"bar"=>"forty-two"}


easy cheasy. parseargs abstracts even further. if a language mod must be
made the answer seems clear: old style keywords land in *args as before, new
style ones land in keys, for example:

def meth *args
p args
end

meth 42 #=> [42]
meth 42, 'foo' => 42 #=> [42, {'foo' => 42}]


def meth *args, **keys
p [args, keys]
end

meth 42 #=> [ [42], {} ]
meth 42, 'foo' => 42 #=> [ [42, {'foo' => 42}], {} ]
meth 42, foo : 42 #=> [ [42, {}], {'foo' => 42} ]
meth 42, 'foo' => 42, foo : 42 #=> [ [42, {'foo' => 42}], {'foo' => 42} ]

i might add that i hope whatever keys object will hash key and symbol
arguments the same so we can do

val = keys['foo']

or

val = keys[:foo]

i hate having to check for both (that's what getopt above does).

2cts.

-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| anything that contradicts experience and logic should be abandoned.
| -- h.h. the 14th dalai lama
===============================================================================

Trans

unread,
Oct 23, 2005, 10:42:04 PM10/23/05
to

Ara.T.Howard wrote:
> it's not that big a deal to do is it? i've abstracted this in alib like so:
>
> harp:~ > cat a.rb
> require 'alib'
> include ALib::Util
>
> def meth *argv
> args, opts = optfilter argv
> foo = getopt 'foo', opts
> bar = getopt 'bar', opts, 'forty-two' # default value
>
> p 'args' => args
> p 'opts' => opts
> p 'foo' => foo
> p 'bar' => bar
> end
>
> meth 'foo', 'bar', 'foo' => 42
>
> harp:~ > ruby a.rb
> {"args"=>["foo", "bar"]}
> {"opts"=>{"foo"=>42}}
> {"foo"=>42}
> {"bar"=>"forty-two"}
>
>
> easy cheasy. parseargs abstracts even further.

That's nice, but then why would we need key args if we'd do this
anyway?

> if a language mod must be
> made the answer seems clear: old style keywords land in *args as before, new
> style ones land in keys, for example:
>
> def meth *args
> p args
> end
>
> meth 42 #=> [42]
> meth 42, 'foo' => 42 #=> [42, {'foo' => 42}]
>
>
> def meth *args, **keys
> p [args, keys]
> end
>
> meth 42 #=> [ [42], {} ]
> meth 42, 'foo' => 42 #=> [ [42, {'foo' => 42}], {} ]
> meth 42, foo : 42 #=> [ [42, {}], {'foo' => 42} ]
> meth 42, 'foo' => 42, foo : 42 #=> [ [42, {'foo' => 42}], {'foo' => 42} ]

>From what I understand this isn't what will happen, but rather

> meth 42, foo : 42 #=> [ [42, {:foo => 42}], {:foo => 42} ]

and

> meth 42, 'foo' => 42, foo : 42 #=> Error

> i might add that i hope whatever keys object will hash key and symbol
> arguments the same so we can do
>
> val = keys['foo']
>
> or
>
> val = keys[:foo]
>
> i hate having to check for both (that's what getopt above does).

Interesting point. Perhaps better then:

val = keys.foo

Would go even better with Evan's mixed parameter object.

def(*parms)
p parms
p parms.named
p parms.foo
end

foo( 1,2,foo:3 )
=> [1,2]
{:foo=>3}
3

T.

ES

unread,
Oct 23, 2005, 11:40:33 PM10/23/05
to

Yeah, but this just seems like fixing the symptoms of a problem
rather than the root cause. I have to say, the further this goes
on, the less I like the Lispish syntax for the sheer convolutedness.
Lisp did things the way it did because of its implementation an
possibly limitations ruby does not suffer from.

Also, and please enlighten me here, I have seen no tangible payback
for the added complexity except for being able to opt out of using
keyword arguments altoghether (Sydney's model creating them implicitly).
Am I missing something? I do not think there is any advantage in
delegation (when implemented as I posted earlier).

> <snip example>
>
> -a

E


Ara.T.Howard

unread,
Oct 24, 2005, 12:06:39 AM10/24/05
to
On Mon, 24 Oct 2005, Trans wrote:

> That's nice, but then why would we need key args if we'd do this anyway?

that was my point ;-) just wondering out loud how important lanuage support
greater than collecting open key/values pairs is...

>> From what I understand this isn't what will happen, but rather
>
>> meth 42, foo : 42 #=> [ [42, {:foo => 42}], {:foo => 42} ]

eek!

>> meth 42, 'foo' => 42, foo : 42 #=> Error

eeeeek!

>> i might add that i hope whatever keys object will hash key and symbol
>> arguments the same so we can do
>>
>> val = keys['foo']
>> or
>>
>> val = keys[:foo]
>>
>> i hate having to check for both (that's what getopt above does).
>
> Interesting point. Perhaps better then:
>
> val = keys.foo

i do like

verbose = keys.value_at(%w( verbose verbosity v )).first

eg - a hash interface.

> Would go even better with Evan's mixed parameter object.
>
> def(*parms)
> p parms
> p parms.named
> p parms.foo
> end
>
> foo( 1,2,foo:3 )
> => [1,2]
> {:foo=>3}
> 3

harp:~ > cat a.rb
require 'parseargs'
include ParseArgs

def meth *argv
pa = parseargs(argv){ args %w( a b ) and kws %w( c d ) }
p pa.arguments.map{|a| a.name}
p pa.keywords.map{|k| k.name}
p pa.a
p pa.b
p pa.c
p pa.d
end

meth 4, 2, 'c' => 'forty', 'd' => 'two'


harp:~ > ruby a.rb
["a", "b"]
["c", "d"]
4
2
"forty"
"two"


;-)

gga

unread,
Oct 24, 2005, 1:42:58 AM10/24/05
to

Yukihiro Matsumoto wrote:
> Hi,
>
> Right syntax is
>
> def function(a, b, c, d:, e: 1, f:)
> end

So if I have default values on both positional and named parameters, it
would look like this?

def function( a, b = 2, c = 1, d: 1, e: 2, f: 3)
end

Hmm...

The reason why pythonist don't need the distinction between
named/positional parameters is that exposing an api also comes down to
common sense. Let's see if an example works as intended.
To make sure it does, I *won't* say which parameters I expect to be
positional parameters in my api and which one's I already locked. I
won't provide any rdocs, either. Let's see if you guess...

def texture( name, smin, tmin, smax, tmax,
filter = 'gaussian', filtersize = 0.5 )
end

Looking at the above, which parameters would you call by name and which
ones by position? Spoiler below...


If you said filter and texture as the named parameters, python's method
probably is on to something.

IMO, parameter default values are so very tighly linked to named
parameters that I almost see no distinction most of the time. I often
don't see positional arguments with defaults. The above function, btw,
is not taken from python. It is taken from probably the oldest api in
existance that has never had a dramatic syntactic change (and where I
first saw what named parameters could do): Renderman. This 3d
shading language api has lasted over 20 years without a change and
afaik, they were the first or one of the first languages to have named
parameters.
And yes, before someone points it out, the texture() call in renderman
is more complex than the above, as it automatically reads from globals
and also works with a single parameter and worse, it is overloaded
based on its return values, making it also a perfect counter-example to
the idea of the rule of positional parameters not having defaults.
Let's see how a python guy would solve this issue...

def texture( name, smin = $s, tmin = $t, smax = $s + $ds, tmax =
$s + $dt,
# named parameters:
filter = 'gaussian', filtersize = 0.5 )

I added only a single comment... in the middle of the function
definition.
Do I really need the interpreter to enforce the above and have to
rewrite all previously written functions to support named parameters
now?

gga

unread,
Oct 24, 2005, 2:22:53 AM10/24/05
to
> Nabu wrote:
>
> def function(a, b, c = "" ; d, e = 1, *f)
> end

Much nicer than what I suggested, for sure. The semicolon is already a
separator in ruby... so there's at least some logic to the symbol.

>From a readability stand-point, having something like:

- Definition:

def function(a, b, c = ""; d, e = 1, *f)
end

- While Invokation is Matz-like:

function 1, 3, "hello", e: 20

..is certainly very readable.

Most definitively not symetrical, thou.

Daniel Schierbeck

unread,
Oct 24, 2005, 7:52:35 AM10/24/05
to
How about this definition syntax (note that `=>' is just being used here
as an example):

def foo(a, b = 1, named c, named d = 2, *args, **keys)
# notice that c and d are local vars
puts a, b, c, d
end

`keys' could also include c and d. `foo' could then be called like this:

foo(1, 2, c => 3, d => 4, e => 5)
foo(1, 2, 3, 4, e => 5)

keys -> {:c => 3, :d => 4, :e => 5}

This would also solve the problem with passing on an argument list,
since named arguments would naturally appear in the `*args' array:

def foo(*args)
bar(*args)
end

foo(1, 2, a => 3, b => 4) -> args = [1, 2, 3, 4]

Only problem is that you can't make your method callable with named
arguments only.


Cheers,
Daniel

Eric Mahurin

unread,
Oct 24, 2005, 11:15:35 AM10/24/05
to
--- Yukihiro Matsumoto <ma...@ruby-lang.org> wrote:

> Hi,
>
> In message "Re: A comparison by example of keyword argument
> styles"
> on Mon, 24 Oct 2005 05:50:39 +0900, Eric Mahurin
> <eric_m...@yahoo.com> writes:
>
> |What use is it to have the named arguments appear twice? I
> |understand the need if you don't have named arguments in the
> |definition (compatibility), but as soon as named arguments
> are
> |specified, it seems to serve no purpose.
>
> It's for method delegation. Currently we do
>
> def foo(*args)
> bar(*args)
> end
>
> for method delegation.

To do the full delegation right now you really need:

def foo(*args, &block)
bar(*args, &block)
end

> Under my proposal, this delegation
> would still
> work fine, since we have named arguments appear twice,
> otherwise we
> must change the code as
>
> def foo(*args, **keys)
> bar(*args, **keys)
> end
>
> everywhere, to just do delegation.

or rather:

def foo(*args, **keys, &block)
bar(*args, **keys, &block)
end

What's wrong with having to do that? The old delegation would
be able to delegate to any of the old non-named argument method
definitions. Existing code would not break. Only when you
start using new named arguments in your method definitions
would you have to fix the delegation methods.

I think you need to choose whether you want separation between
named and positional arguments (like lisp and command-line
options/args) or not (like python/sydney). And go with it.
Having named arguments appear in the positional *args does not
show good separation - what you want I think.

> |Also, like we have array splatting when you call a method, I
> |think hash splatting would also be useful. matz said that
> |hashes would be automatically splatted if they were the last
> |argument, but this results in ambiguity:
> |
> |def foo(a,b={},c:2,**keys) ... end
> |
> |foo("a",{:x => 1,:y => 2})
> |
> |Does the above result in:
> |
> |a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}
> |
> |or:
> |
> |a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}
>
> The former. Keyword argument uses the last remaining hash.

This contradicts what you said above about method delegation.
If we had this delegation with the above foo:

def bar(*args)
foo(*args)
end

bar("a", x: 1, y: 2)
# bar: args = ["a",{:x => 1, :y => 2}]
# foo: a = "a", b = {:x => 1,:y => 2}, c = 2, keys = {}

That's not what you wanted for delegating. It should be:

foo: a = "a", b = {}, c = 2, keys = {:x => 1,:y => 2}

But then if you choose that, you have no way of passing a hash
to the last positional argument and giving no named arguments
(assuming they all have defaults).

I think with named arguments you should not give special
meaning to Hash or you'll run into the same problems you had
with multiple-value returns and assignments that you had with
Array. Explicitly splatting/unsplatting a Hash for named
arguments makes sense, but I don't think you should tie Hash as
part of the definition of named arguments.

> |I'm hoping that we have enough reflection for these named
> |arguments like #arity. I'm thinking that with named
> arguments
> |a potential simple application would be as a spec for
> handling
> |command-line options (named arguments). I'd like to see all
> of
> |the keywords and defaults accessible from Proc/Method
> objects.
> |It'd be nice to have access to defaults of positional args
> |while wer'e asking.
>
> Accepting keywords should be obtained from some kind of
> reflection
> API, although the API is not fixed yet. But I'm not sure
> default
> values can be accessed since they are arbitrary expression,
> and we
> have no good way to represent pre-evaluated expression in
> Ruby (unlike
> in Lisp, where we can use S expression).

Sorry, I forgot that defaults can be expressions. I guess you
could have something that just says whether an arg (positional
or named) has a default or not. Another option is to be able
to access the default as a Proc. To evaluate the default,
you'd just #call it like any other Proc.

> |Since Ruby 2 will also be completely redoing how
> |multiple-values are handled, why not also consider being
> able
> |to name your return values? If a method returns a bunch of
> |attributes, it would be nice for the caller to be able to
> pick
> |what they want.
>
> I have no good idea of multiple value binding for named
> values
> (i.e. syntax). Do you?
>
> matz.

Actually, I do. If you put the ability to handle named
arguments in a multi-assign, you'll have it. The LHS would
look like argument definitions in a def (except defaults aren't
allowed) and the RHS (or return) would look like a method call.
The problem is that this will force the named argument to be
put in a variable of the same name when assigning to the LHS.
To fix this problem, I propose that you be allowed to specify a
different local variable name for a named argument in a method
definition or LHS:

def foo(
a, # position: 0, local var: a, required
b="b", # position: 1, local var: b, default: "b"
*args, # position: 2..-1, local var: args
w:, # name: w, local var: w, required
x:c, # name: x, local var: c, required
y:="y", # name: y, local var: y, default: "y"
z:d="z",# name: z, local var: d, default: "z"
**keys) # name: others, local var: keys
...
# maybe w: could be made equivalent to w:w
return a,b,*args,w:w,x:c,y:y,z:d,**keys
end

# only care about pos:0 and name:x - throw out the rest
aa,x:xx = foo(0,1,2,w:3,x:4,m:5)

Like you allow discarded positional args ("_"), you could also
allow discarded named args (name:_[=default]). And "**" like
"*" could mean accept any other keys but throw them out.

BTW, I'd still like to see the ability to specify required
positional args after the *args and/or default positional args.
I see no reason why any of this named argument stuff would
conflict with this (RCR 315).


__________________________________
Yahoo! FareChase: Search multiple travel sites in one click.
http://farechase.yahoo.com


Louis J Scoras

unread,
Oct 24, 2005, 3:30:02 PM10/24/05
to
Right, so this is probably a really dumb idea, but I was just having a
little bit of fun. It would be cool if you could define methods like this:

define :foo do
required :bar, :baz
optional :request => 'useless'
named :side,
:meat => 'fish'
body do
puts "Good, I got to say #{foo}#{bar}."
puts "You thought of my third request was #{request}"
puts "For dinner we have #{meat}"
if side
puts "With a side of #{side}"
end
end
end

foo 'hello ', 'world', :meat => 'steak', :side => 'potatoes'

That is the first few times you wrote a definition like that. Then it would
get very old very quickly I'm assuming ;)

Trans

unread,
Oct 24, 2005, 4:33:14 PM10/24/05
to
Widdle it:

def foo( required :bar, :baz ; optional :request=>'useless' ; named
:side, :meat=>'fish' )

def foo( bar, baz ; optional :request=>'useless' ; named :side,
:meat=>'fish' )

def foo( bar, baz, request='useless', keys: side, meat=>'fish' )

def foo( bar, baz, request='useless', side=>nil, meat=>'fish' )

T.

Louis J Scoras

unread,
Oct 24, 2005, 4:51:06 PM10/24/05
to
On 10/24/05, Trans <tran...@gmail.com> wrote:
>
> Widdle it:


*agrees*

def foo( required :bar, :baz ; optional :request=>'useless' ; named
> :side, :meat=>'fish' )
>
> def foo( bar, baz ; optional :request=>'useless' ; named :side,
> :meat=>'fish' )
>

That one is very much like the lisp defun if I'm not mistaken.

def foo( bar, baz, request='useless', keys: side, meat=>'fish' )
>
> def foo( bar, baz, request='useless', side=>nil, meat=>'fish' )


That looks reasonable. What's wrong with that? In the calling code it
wouldn't be ambiguous because there's: a fixed number of required
parameters; optional parameters come after the required ones, and any
keywords are specified with '=>' as they are currently.

Why are keyword parameters needed anyway? Is there a problem with the
implicit hash?


--
Lou

Ara.T.Howard

unread,
Oct 24, 2005, 5:03:39 PM10/24/05
to

harp:~ > cat a.rb
require 'parseargs'
include ParseArgs

def meth *argv
pa =

parseargs(argv) do
req_arg 'foo', 'bar'
opt_arg 'request' => 'useless'
opt_kw 'side'
opt_kw 'meat' => 'fish'
end

puts <<-txt
Good, I got to say #{ pa.foo } #{ pa.bar }.
You thought of my third request was #{ pa.request }
For dinner we have #{ pa.meat }
txt

if pa.side
puts "With a side of #{ pa.side }"
end
end

meth 'hello ', 'world', 'useless', :meat => 'steak', :side => 'potatoes'

harp:~ > ruby a.rb
Good, I got to say hello world.
You thought of my third request was useless
For dinner we have steak
With a side of potatoes


note. it's impossible to determine, if an argument is optional (your 'request'
above) if the last hash passed __is__ that optional argument itself or if it's
the set of keywords. therfore you must pass 'useless' for the request in this
case - if you think about it the parsing is otheriwse impossible.

cheers.

Berger, Daniel

unread,
Oct 24, 2005, 5:09:41 PM10/24/05
to
> -----Original Message-----
> From: Louis J Scoras [mailto:louis.j...@gmail.com]
> Sent: Monday, October 24, 2005 2:51 PM
> To: ruby-talk ML
> Subject: Re: A comparison by example of keyword argument styles
>
>
> On 10/24/05, Trans <tran...@gmail.com> wrote:
> >
> > Widdle it:
>
>
> *agrees*
>
> def foo( required :bar, :baz ; optional :request=>'useless' ; named
> > :side, :meat=>'fish' )
> >
> > def foo( bar, baz ; optional :request=>'useless' ; named :side,
> > :meat=>'fish' )
> >
>
> That one is very much like the lisp defun if I'm not mistaken.
>
> def foo( bar, baz, request='useless', keys: side, meat=>'fish' )
> >
> > def foo( bar, baz, request='useless', side=>nil, meat=>'fish' )
>
>
> That looks reasonable. What's wrong with that?

What's wrong with making them all implicit instead of forcing me to add
this extra, ugly syntax?

People that support explicit syntax for keyword arguments in method
definitions shall be damned to the committee that combs over every
single method in the core and standard library and figures out which
parameters will support keywords and which ones won't. They will also
be responsible for explaining their rationale to the rest of us, and
dealing with all subsequent arguments that result. They will ALSO be
relegated to answering all future emails from newbies wondering why some
parameters support keywords and some don't.

Regards,

Dan


Ara.T.Howard

unread,
Oct 24, 2005, 5:16:16 PM10/24/05
to
On Tue, 25 Oct 2005, Louis J Scoras wrote:

> On 10/24/05, Trans <tran...@gmail.com> wrote:
>>
>> Widdle it:
>
>
> *agrees*
>
> def foo( required :bar, :baz ; optional :request=>'useless' ; named
>> :side, :meat=>'fish' )
>>
>> def foo( bar, baz ; optional :request=>'useless' ; named :side,
>> :meat=>'fish' )
>>
>
> That one is very much like the lisp defun if I'm not mistaken.
>
> def foo( bar, baz, request='useless', keys: side, meat=>'fish' )
>>
>> def foo( bar, baz, request='useless', side=>nil, meat=>'fish' )
>
>
> That looks reasonable. What's wrong with that? In the calling code it
> wouldn't be ambiguous because there's: a fixed number of required
> parameters; optional parameters come after the required ones, and any
> keywords are specified with '=>' as they are currently.

not really, think about it

request = 'side' => 'beans', 'meat' => 'tofu'

foo 'bar', 'baz', request

have you passed request as 'request' or the keywords? how bout here:

foo 'bar', 'baz', 'side' => 'beans', 'meat' => 'tofu'

and here

foo 'bar', 'baz', nil, 'side' => 'beans', 'meat' => 'tofu'

is request 'nil' and therfore is not assigned the default value? or is nil
clobbered with the default? if it's clobbered how can you ever call a method
that accepts an optional argument with default with a value of nil and not
have it clobbered? eg. how could you do this:

def foo optional = 42
end

how do you call it with optional == nil?

if this works

foo nil

then this cannot work

def foo required, optional = 42, keyword => 'forty-two'
end

since you cannot call foo with both a keyword AND get the default value for
optional. this won't work

foo 42, 'keyword' => 40 + 2

since you are simply passing a hash as the value for optional. and keyword is
not set - and this won't work

foo 42, nil, 'keyword' => 40 + 2

since now optional is nil and not the default value of 42.

i think you cannot ever have both trailing optional arguments AND keywords
with current ruby calling conventions since it will always be impossible to
determine whether the last hash is a value for an optional argument or the set
of keywords. the only way is to have a syntax that calls methods with
keywords that are not an inlines hash, eg

foo 42, keyword : 42.0 # optional gets default value
foo 42, keyword => 42.0 # optional IS a hash , keyword is not given

when i was coding parseargs all this became apparent very quickly. trying to
write a parser for any proposed syntax is a good exercise that shows how nice
a real keyword syntax might make things.

regards.

Louis J Scoras

unread,
Oct 24, 2005, 5:16:53 PM10/24/05
to
On 10/24/05, Ara.T.Howard <Ara.T....@noaa.gov> wrote:
>
>
>
> meth 'hello ', 'world', 'useless', :meat => 'steak', :side => 'potatoes'
>
> harp:~ > ruby a.rb
> Good, I got to say hello world.
> You thought of my third request was useless
> For dinner we have steak
> With a side of potatoes
>
>
> note. it's impossible to determine, if an argument is optional (your
> 'request'
> above) if the last hash passed __is__ that optional argument itself or if
> it's
> the set of keywords. therfore you must pass 'useless' for the request in
> this
> case - if you think about it the parsing is otheriwse impossible.
>
>
Couldn't you require an explicit hash then, if it is intended to be slurped
into the optional parameter? You need to magically realize that this is a
hash in the first place.

meth 'hello ', 'world', :meat => 'steak', :side => 'potatoes'

response = 'useless'
meat = 'steak'
side = 'potatoes'

Would be distinguished from this:

meth 'hello ', 'world', {:meat => 'steak', :side => 'potatoes'}

response = {:meat => 'steak', :side => 'potatoes'}

And this:

meth 'hello ', 'world', {:meat => 'steak'}, :side => 'potatoes'

response = {:meat => 'steak'},
side = 'potatoes'

Ara.T.Howard

unread,
Oct 24, 2005, 5:24:58 PM10/24/05
to

harp:~ > cat a.rb
def meth *a, &b
p a
end

meth 'hello', 'world', :meat => 'steak', :side => 'potatoes'
meth 'hello', 'world', {:meat => 'steak', :side => 'potatoes'}


harp:~ > ruby a.rb
["hello", "world", {:meat=>"steak", :side=>"potatoes"}]
["hello", "world", {:meat=>"steak", :side=>"potatoes"}]


these cannot be distinguished.

Louis J Scoras

unread,
Oct 24, 2005, 5:28:57 PM10/24/05
to
> What's wrong with making them all implicit instead of forcing me to add
> this extra, ugly syntax?


Well, my gut instinct was that this is breaking encapsulation: you didn't
intend for that symbol to be in the public interface. But the more I think
about it, how often do you changed the name of a parameter like this after
the API is solidified? The parameter in that position can't change it's
semantic meaning anyway. So you're probably right.

It just feels wrong, as I'm sure being forced to explicitly define how
arguments are specified feels wrong to you.


--
Lou

Berger, Daniel

unread,
Oct 24, 2005, 5:44:52 PM10/24/05
to

> -----Original Message-----
> From: Louis J Scoras [mailto:louis.j...@gmail.com]
> Sent: Monday, October 24, 2005 3:29 PM
> To: ruby-talk ML
> Subject: Re: A comparison by example of keyword argument styles
>
>

> > What's wrong with making them all implicit instead of forcing me to
> > add this extra, ugly syntax?
>
>
> Well, my gut instinct was that this is breaking
> encapsulation: you didn't intend for that symbol to be in the
> public interface. But the more I think about it, how often do
> you changed the name of a parameter like this after the API
> is solidified?

Never, unless someone suddenly comes along and tells you that your
parameter names can now be used as keywords. :) But, once you realize
what the rules are, you'll always use sensical parameter names.

> It just feels wrong, as I'm sure being forced to explicitly
> define how arguments are specified feels wrong to you.

Well, we've got a great use case in the Python community, where they've
had implicit keywords since 1.3 afaik. If it were a problem in program
design they would have yanked it by now. Or at the very least, we would
have heard lots of screaming. We haven't.

Note also that I didn't support the notion of implicit keywords because
of Python (or any other language). I only learned later about how
Python behaves.

Regards,

Dan


Trans

unread,
Oct 24, 2005, 6:21:50 PM10/24/05
to

Ara.T.Howard wrote:

> i think you cannot ever have both trailing optional arguments AND keywords
> with current ruby calling conventions since it will always be impossible to
> determine whether the last hash is a value for an optional argument or the set
> of keywords. the only way is to have a syntax that calls methods with
> keywords that are not an inlines hash, eg
>
> foo 42, keyword : 42.0 # optional gets default value
> foo 42, keyword => 42.0 # optional IS a hash , keyword is not given

Ah, at first I was gogin to say "STOP! You've got this all distorted.
These are parameters, not hash keys. Related but different. So why are
you using strings? It's this:

foo 42, keyword => 40 + 2

There is no ambiguity."

But now I see you get to this To which I say: Exactly. This is how it
ought to be -- IF done this way. Matz implementation actually is NOT
like this though and has worse problems some of which you describe
above.

> when i was coding parseargs all this became apparent very quickly. trying to
> write a parser for any proposed syntax is a good exercise that shows how nice
> a real keyword syntax might make things.

What do you mean by real?

T.

Ara.T.Howard

unread,
Oct 24, 2005, 6:29:12 PM10/24/05
to
On Tue, 25 Oct 2005, Trans wrote:

> Ara.T.Howard wrote:
>
>> i think you cannot ever have both trailing optional arguments AND keywords
>> with current ruby calling conventions since it will always be impossible to
>> determine whether the last hash is a value for an optional argument or the
>> set of keywords. the only way is to have a syntax that calls methods with
>> keywords that are not an inlines hash, eg
>>
>> foo 42, keyword : 42.0 # optional gets default value
>> foo 42, keyword => 42.0 # optional IS a hash , keyword is not given
>
> Ah, at first I was gogin to say "STOP! You've got this all distorted. These
> are parameters, not hash keys. Related but different. So why are you using
> strings? It's this:
>
> foo 42, keyword => 40 + 2
>
> There is no ambiguity."
>
> But now I see you get to this To which I say: Exactly. This is how it ought
> to be -- IF done this way. Matz implementation actually is NOT like this
> though and has worse problems some of which you describe above.

it's slippery all right.

>> when i was coding parseargs all this became apparent very quickly. trying
>> to write a parser for any proposed syntax is a good exercise that shows how
>> nice a real keyword syntax might make things.
>
> What do you mean by real?

i mean something other that collected trailing hash keys.

mind you, i'm happy with the current situation. but if syntax support would
be added to ruby it's a slippery slope when you through optional arguments,
and trailing open hashes into the mix.

Trans

unread,
Oct 24, 2005, 6:37:26 PM10/24/05
to

> def meth *argv
> pa =
> parseargs(argv) do
> req_arg 'foo', 'bar'
> opt_arg 'request' => 'useless'
> opt_kw 'side'
> opt_kw 'meat' => 'fish'
> end

I idea is good but may I suggest it be a little less "cryptic"?
Something more like:

def meth *parm
parm = Parameters.new(parm) do
args :foo, :bar, :request => 'useless'
keys :side => nil, :meat => 'fish'
end
parm.foo
...

You could also to set parm automatically, and of course a #parameters
constructor method is fine if you prefer, producing:

def meth *parm
parameters(parm) do
args :foo, :bar, :request => 'useless'
keys :side => nil, :meat => 'fish'
end
parm.foo
...

T.

It is loading more messages.
0 new messages