Default values for method arguments

Hi all,

Probably I'm trying something impossible, but when giving default
values for arguments to a method call, do I have to give default-values
for *all* arguments?

   irb(main):001:0> class A
   irb(main):002:1> def a(b = 0, c, d = '', e)
   irb(main):003:2> puts b, c, d, e
   irb(main):004:2> end
   irb(main):005:1> end
   SyntaxError: compile error
   (irb):2: syntax error
     def a(b = 0, c, d = '', e)
                    ^
   (irb):2: syntax error
   (irb):5: syntax error
           from (irb):5

And also when giving default-values to all arguments, omitting
arguments when calling the method doesn't seem to be a succes:

   irb(main):001:0> class B
   irb(main):002:1> def b(c = 0, d = 1, e = 2)
   irb(main):003:2> puts c, d, e
   irb(main):004:2> end
   irb(main):005:1> end
   => nil
   irb(main):006:0> B.new.b(1,2,3)
   1
   2
   3
   => nil
   irb(main):007:0> B.new.b(1,3)
   SyntaxError: compile error
   (irb):7: syntax error
   B.new.b(1,3)
              ^
           from (irb):7

Is it impossible or I'm I just coding it wrong?

Cheers,
Paul

Probably I'm trying something impossible, but when giving default
values for arguments to a method call, do I have to give default-values
for *all* arguments?

No, but all the arguments that don't have defaults must come before (to the left of) those that do.

And also when giving default-values to all arguments, omitting
arguments when calling the method doesn't seem to be a succes:

   irb(main):001:0> class B
   irb(main):002:1> def b(c = 0, d = 1, e = 2)
   irb(main):003:2> puts c, d, e
   irb(main):004:2> end
   irb(main):005:1> end
   => nil
   irb(main):006:0> B.new.b(1,2,3)
   1
   2
   3
   => nil
   irb(main):007:0> B.new.b(1,3)
   SyntaxError: compile error
   (irb):7: syntax error
   B.new.b(1,3)
              ^
           from (irb):7

Again, you can only leave out arguments that come after (to the right of) those you provide.

Is it impossible or I'm I just coding it wrong?

You just need to switch strategies. Use Ruby's simulated keyword arguments for something like this:

>> def test(args)
>> puts args.values_at(:a, :b, :c)
>> end
=> nil
>> test :a => 1, :c => 2
1
nil
2
=> nil

Hope that helps.

James Edward Gray II

···

On Dec 6, 2006, at 8:05 AM, paul wrote:

You just need to switch strategies. Use Ruby's simulated keyword
arguments for something like this:

>> def test(args)
>> puts args.values_at(:a, :b, :c)
>> end
=> nil
>> test :a => 1, :c => 2
1
nil
2
=> nil

Hi James,

The Simulated Keyword Arguments you talk about are a little abstract to
me, but I think I get the idea. I suppose in the example above I would
have to add a couple of lines to define the default values...
This way, the general idea is the same as the following?

irb(main):001:0> def test(args)
irb(main):002:1> args['a'] = 'defaultA' unless args.has_key?('a')
irb(main):003:1> args['b'] = 'defaultB' unless args.has_key?('b')
irb(main):004:1> args['c'] = 'defaultC' unless args.has_key?('c')
irb(main):005:1> puts args.indexes('a', 'b', 'c')
irb(main):006:1> end
=> nil
irb(main):007:0> test({'a' => 'someA', 'c' => 'someC'})
(irb):5: warning: Hash#indexes is deprecated; use Hash#values_at
someA
defaultB
someC
=> nil

An additional question: do you know a link where I can find more on
those Simulated Keyword Arguments? I did some googling, but it turned
up with nothing on:
ruby "Simulated Keyword Arguments"

Those colons you use before the variable-names are a little like magic
to me. (though I checked, without those colons, you're example above
wouldn't have worked...) :slight_smile:

Cheers,
Paul

The Simulated Keyword Arguments you talk about are a little abstract to
me, but I think I get the idea.

My fault, I did not describe them very well. Here are the critical bits of information:

If a method call ends with some arguments that look like a Hash definition (using the fat arrows =>), Ruby collects those and passes a single Hash to the method in their place. You can then work with the Hash normally.

irb(main):001:0> def test(args)
irb(main):002:1> args['a'] = 'defaultA' unless args.has_key?('a')
irb(main):003:1> args['b'] = 'defaultB' unless args.has_key?('b')
irb(main):004:1> args['c'] = 'defaultC' unless args.has_key?('c')
irb(main):005:1> puts args.indexes('a', 'b', 'c')
irb(main):006:1> end
=> nil
irb(main):007:0> test({'a' => 'someA', 'c' => 'someC'})
(irb):5: warning: Hash#indexes is deprecated; use Hash#values_at
someA
defaultB
someC
=> nil

Another way to set defaults:

>> def test(args)
>> args = { "a" => "default a",
?> "b" => "default b",
?> "c" => "default c" }.merge(args)
>> puts args.values_at("a", "b", "c")
>> end
=> nil
>> test "a" => "some a", "c" => "some c"
some a
default b
some c
=> nil

An additional question: do you know a link where I can find more on
those Simulated Keyword Arguments?

See Collecting Hash Arguments at the bottom of:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_methods.html

Those colons you use before the variable-names are a little like magic
to me. (though I checked, without those colons, you're example above
wouldn't have worked...) :slight_smile:

Those are just Symbol objects. Don't lose too much sleep over them yet, as you can see from the new example Strings work fine too.

James Edward Gray II

···

On Dec 6, 2006, at 9:30 AM, paul wrote:

You just need to switch strategies. Use Ruby's simulated keyword
arguments for something like this:

>> def test(args)
>> puts args.values_at(:a, :b, :c)
>> end
=> nil
>> test :a => 1, :c => 2
1
nil
2
=> nil

Hi James,

The Simulated Keyword Arguments you talk about are a little abstract to
me, but I think I get the idea. I suppose in the example above I would
have to add a couple of lines to define the default values...
This way, the general idea is the same as the following?

irb(main):001:0> def test(args)
irb(main):002:1> args['a'] = 'defaultA' unless args.has_key?('a')
irb(main):003:1> args['b'] = 'defaultB' unless args.has_key?('b')
irb(main):004:1> args['c'] = 'defaultC' unless args.has_key?('c')
irb(main):005:1> puts args.indexes('a', 'b', 'c')
irb(main):006:1> end
=> nil
irb(main):007:0> test({'a' => 'someA', 'c' => 'someC'})
(irb):5: warning: Hash#indexes is deprecated; use Hash#values_at
someA
defaultB
someC
=> nil

Try this-- it's more concise, and you probably won't feel the need
for more syntactic magic after that.

def test(args)
  args[:a] ||= 'defaultA'
  args[:b] ||= 'defaultB'
  args[:c] ||= 'defaultC'
  puts args.indexes(:a, :b, :c)
end

An additional question: do you know a link where I can find more on
those Simulated Keyword Arguments? I did some googling, but it turned
up with nothing on:
ruby "Simulated Keyword Arguments"

Those colons you use before the variable-names are a little like magic
to me. (though I checked, without those colons, you're example above
wouldn't have worked...) :slight_smile:

The colons make them into symbol objects.

···

On Wed, 06 Dec 2006 07:27:00 -0800, paul wrote:

Cheers,
Paul

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

but this breaks

   test :a => false

as does this

   test :a => nil

and this

   test 'a' => true

regards.

-a

···

On Thu, 7 Dec 2006, Ken Bloom wrote:

Try this-- it's more concise, and you probably won't feel the need
for more syntactic magic after that.

def test(args)
args[:a] ||= 'defaultA'
args[:b] ||= 'defaultB'
args[:c] ||= 'defaultC'
puts args.indexes(:a, :b, :c)
end

--
if you want others to be happy, practice compassion.
if you want to be happy, practice compassion. -- the dalai lama

Ken Bloom wrote:

Try this-- it's more concise, and you probably won't feel the need
for more syntactic magic after that.

def test(args)
  args[:a] ||= 'defaultA'
  args[:b] ||= 'defaultB'
  args[:c] ||= 'defaultC'
  puts args.indexes(:a, :b, :c)
end

I find:

def test(args)
  realargs = {:a => 'defaultA',
   :b => 'defaultB',
   :c => 'defaultC'}.update(args)

  puts args.indexes(:a, :b, :c)
end

more readable. Preferrably extracting the default values into constants
before the method definition and (deep?)cloning the hash.

Also, your code clobbers the hash put into args by putting in values.
This might not cause bugs most of the case, but might in case someone
passes in an actual hash, so I'd just stay on the safe side.

David Vallner