Hacker News new | past | comments | ask | show | jobs | submit login
Keyword Arguments: Ruby, Clojure, Common Lisp (briancarper.net)
42 points by bgray on June 25, 2011 | hide | past | favorite | 19 comments



More like "how Ruby and Clojure don't really support keyword arguments". Unless you can do something like:

    >>> def foo(a,b):
    ...   print a,b
    ... 
    >>> foo(b=1,a=2)
    2 1
then you don't support keyword arguments, you just have some hack for stuffing parameters into a hash. In fact, MacRuby had to add syntax to Ruby[1] in order to be able to represent Objective C keyword arguments.

[1] http://www.macruby.org/documentation/rubycocoa-to-macruby.ht...


> In fact, MacRuby had to add syntax to Ruby[1] in order to be able to represent Objective C keyword arguments.

On the other hand, Objective-C's keyword messages, inherited from Smalltalk, are very different from Python's keyword arguments (to the point that PyObjC can not map one to the other, and uses name mangling for ObjC method calls instead, similar to RubyCocoa's method): in Obj-C, the keywords are part of the method name (in fact, they are the method name) and changing their order or adding new arguments will change the message sent to the object.

Not so in Python, C#, or using Ruby's hash-hack, where keyword arguments are basically a `String -> Any` map sent to the method.

As a result, even if Ruby implemented "proper" keyword arguments it's quite unlikely unlikely they would match Obj-C's, and MacRuby would still have to implement their own.


I find Python inelegant in general but Python's support for keyword arguments strikes the best balance of simplicity and flexibility in any language I've used.


Python's argument conventions are even more flexible; they actually work by passing a tuple of positional arguments and a dictionary of keyword arguments, and unpacking/repacking according to the signature of each function. You can pass any iterable as positional arguments and any mapping as keyword arguments. You can also retrieve the positional and keyword arguments inside a callable as a tuple and dictionary. It's the best calling convention I've ever seen.


Isn't being able to give functions as a default keyword argument more or less obvious when functions are first-class objects instead of it being insane? It's something that I use several times in any decent sized project.

For my bot for the current Google AI challenge I use A* pathfinding and one of the keyword args is the function for getting a node's neighbours.


Yes, all these languages support that. My CL is rusty, and it's not clear from the article, but I think he's talking about providing a function to calculate the default value from some of the other args.


Ruby has a penchant for giving you more than enough rope to hang yourself on, and "Ruby keyword arguments" are no different. I've seen them used in the wild. It's horrendous.

The code I had to update was poorly written, but the functions with "keyword arguments" were practically incomprehensible _because I didn't even know what their parameters were_. Furthermore, the interactions between these "keyword arguments" wasn't documented anywhere. Sometimes supplying one keyword demanded that another keyword also be supplied, less the function quietly fails.

Finally, there's no way to make a "keyword argument" a required argument. Every function I saw with keyword arguments was littered with "bar = foo.key?(:bar) ? foo[:bar] : default_value" or "throw Exception if not foo.key?(:bar)"

Don't use hashes as a replacement for argument lists in Ruby. Hack the Ruby source and add real keyword arguments.

edit: added another example


Well, keyword arguments can be used well in ruby, though clearly, in the code you've been dealing with they haven't.

Some guidelines. Use .merge for default values, not ternary operators. Keep it minimal. Rails does a good job of using keywords for stuff that's optional, and positional arguments for stuff that isn't. For instance

    link_to 'My Website', 'http://example.net', :class => 'my-css-class'.
Here, the arguments you need, the link title and href are non-optional positional args. HTML attributes OTOH are option hash args..

It sounds like in the code you've inherited, though I can't be sure, there are fairly complicated hashes being passed around all kinds of places. These should probably be objects, not hashes, in the first place. I'll admit though, I can't be certain from my limited vantage point.


I think the hashes instead of objects paradigm contributed to my frustration.

I ended up turning parts of the hashes into objects and parts into parameters.

You and your sibling post provide some decent guidelines and approaches to default arguments. My experience with Ruby has lead me to believe that it's an awesome language, but a language which I'd be very careful about with whom I collaborated.


Here's an example of how I use the hash as keyword arguments. (Minus the documentation

    def save_record(record, options={}, &block)
      return nil if record.nil?
      options = {
        :add_params => {},
        :as => nil,
        :without_protection => false,
        :params => params[record.class.name.underscore.to_sym],
        :user => current_user,
      }.update options
The important part is: options = {}.update(options)

This pattern works very well for providing defaults and some documentation on what options are available. I still document the options before the function.


He spends a lot of time on the syntactic ambiguities of keyword arguments in Ruby when calling without parens. I understand how that's annoying, but how hard would it be to just put the parentheses back? He seems to be making a mountain of a molehill on that point.


Seriously. I can't think of any language feature in any other language that is heaped with so much passion (both positive and negative), while being entirely mundane.


Optional parens are great for building DSLs and bad for everything else.

As a rule of a thumb, I don't omit parens outside macros like `before_filter :smth` or `validates_presence_of :smth` or RSpec DSL `it "should ..." do`.


A 2000 words article on keyword arguments which fails to mention any of Python, Objective-C and Smalltalk?


I suppose this is an article about keyword arguments in Ruby, Clojure and Common Lisp.


I've never found a situation where keyword arguments are a better choice than setters. Setters are dynamic, you can override their implementation. Keyword args only let you override the method that receives them, which provides less granularity and leads to duplication (assuming there is more than one method that accepts a shared arg).


I've never found a situation where keyword arguments are a better choice than setters.

When you're programming in a functional style, perhaps? The idea of a setter doesn't make much sense in Clojure where the native data structures are immutable, implementation inheritance is strongly discouraged and state changes require a little more work than "x = y".


quote: Positional arguments require mentally lining up the 7th argument in your function call with the 7th argument in the function signature, and so on.

If your function has 7 arguments, consider refactoring


If your refactoring is to make a 7-args function into a builder object (because what you're building actually needs those arguments), you're better off with keyword arguments.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: