Peter's Blog

Redefining the Impossible

Ruby != Python WRT default argument values


Found another ruby gotcha when calling methods declared with default argument values:

irb(main):004:0> def a( b=1,c=2,d=3)
irb(main):005:1> print "#{b} #{c} #{d}\n"
irb(main):006:1> end
=> nil
irb(main):007:0> a(c=23)
23 2 3
=> nil

A python programmer would have expected this to print

2 23 3

as when calling the function we are saying we want c to be 23 and the other arguments to be left at their default values. Ruby appears to be ignoring the 'c=' bit when the function is being called so the first argument 'b' gets the value 23.

Pity, this python trick simplifies calling functions with lots of default parameters: you don't have to get the order of the parameters right or specify the correct default values of arguments before the one you are having to specify a value for. I should be calling this with:

irb(main):007:0> a(b=1, c=23)

i.e passing 'b=1' even though the declaration should tell ruby what the default for that should be. The 'b=' and 'c=' are only serving to help me selfdocument my code.

Ruby's behaviour is C/C++ish i.e. primitive.

UPDATE:

O'Reilly Ruby Cookbook:

   1  def fun_with_text(text, args={})
   2    text = text.upcase if args[:upcase]
   3    text = text.downcase if args[:downcase]
   4    if args[:find] and args[:replace]
   5      text = text.gsub(args[:find], args[:replace])
   6    end
   7    text = text.slice(0, args[:truncate_at]) if args[:truncate_at]
   8    return text
   9  end
  10  
  11  fun_with_text("Foobar", {:upcase => true, :truncate_at => 5})
  12  # => "FOOBA"
  13  fun_with_text("Foobar", :upcase => true, :truncate_at => 5)
  14  # => "FOOBA"
  15  fun_with_text("Foobar", :find => /(o+)/, :replace => '\1d', :downcase => true)
  16  # => "foodbar"

Filed under: gotcha noob ruby

ars Says:

Interesting. So, Ruby doesn't really have keyword arguments, only positional arguments? Unless you use some kind of varargs/dictionary, I guess (from the cookbook example).

BTW, I think you meant to say that a Python programmer would expect "1 23 3" as output rather than "2 23 3".

Peter Says:

Reading this again I see what is going on:

def a(b)
  print b
end

a(b=9)
=> 9

print b
=> 9

so what happens is that ruby takes the 'b=9' in the function arguments as an assignment, sets b to 9 and then calls the function with the value 9. At the end we are left with a new variable with the value b.

This is exactly what a c programmer would expect.

Thanks for the correction.

Peter

Have Your Say

I welcome constructive comments or questions but I reserve the right to delete any comments that displease me.

Who are you?

(Optional) If you enter an email address here I might email you back. Your email address will not be sold to spammers or shown anywhere

What do you have to say?