Keyword Arguments: Ruby, Clojure, Common Lisp
briancarper.net
briancarper.net
>>> 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...
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.
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.
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
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 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.
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.
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`.
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".
If your function has 7 arguments, consider refactoring