Wrong results using named arguments

Source:

[a.rb]
class A

       attr_accessor :id
       attr_accessor :name

       def initialize(id = nil, name = nil)
               @id = id
               @name = name
       end
end

[test.rb]
require 'a'

a1 = A.new(:name => "test")
a2 = A.new(:name => "test2")

p a1
p a2

Results:
#<A:0x28c2d80 @id={:name=>"test"}, @name=nil>
#<A:0x28c2678 @id={:name=>"test2"}, @name=nil>

I expected:

#<A:0x28c2d80 @id=nil, @name="test">
#<A:0x28c2678 @id=nil, @name="test2">

So what nuby mistake am I making?

Thanks,
Jason

Jason Vogel wrote:

So what nuby mistake am I making?

Posting the same message six hours after receiving a raft of helpful replies
to the first copy of your message?

···

--
Paul Lutus
http://www.arachnoid.com

Sorry about the repost. Initially, I thought the original post went
successfully, but then when I went to check on it, it didn't show up...
suck.

I thought that the keyword arguments support was in Ruby 1.8. I'm used
to coding Oracle PL/SQL, so it seems really natural to me.

I had seen the hash stuff, but those were all posts about 1.6.

Thanks everyone for the replies, I'll keep going.
Jason

···

On Nov 29, 4:22 pm, Paul Lutus <nos...@nosite.zzz> wrote:

Jason Vogel wrote:
> So what nuby mistake am I making?Posting the same message six hours after receiving a raft of helpful replies
to the first copy of your message?

--
Paul Lutushttp://www.arachnoid.com

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?
- How do I handle required vs. optional arguments?
- Provide some sort of clue to the calling routines what the argument
"names" are?
- Is there a way to enumerate the valid choices for values (e.g. colors
= [red,white,blue])

Jason

···

On Nov 29, 4:22 pm, Paul Lutus <nos...@nosite.zzz> wrote:

Jason Vogel wrote:
> So what nuby mistake am I making?Posting the same message six hours after receiving a raft of helpful replies
to the first copy of your message?

--
Paul Lutushttp://www.arachnoid.com

Jason Vogel wrote:

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?

Initially:

@hash = { key => arg, key => arg, ... }

Then:

@hash[key] = arg # from initializer arguments

- How do I handle required vs. optional arguments?

Please explain. Ordinarily if a required argument is not provided, the call
fails:

... wrong number of arguments (0 for 1) (ArgumentError)

- Provide some sort of clue to the calling routines what the argument
"names" are?

Is this still a constructor for a class?

Perhaps it would be better, rather than asking a lot of hypothetical
questions, for you to say what you are trying to accomplish with your code.

- Is there a way to enumerate the valid choices for values (e.g. colors
= [red,white,blue])

Yes, but it is a bit involved.

···

--
Paul Lutus
http://www.arachnoid.com

Jason Vogel wrote:

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?
- How do I handle required vs. optional arguments?
- Provide some sort of clue to the calling routines what the argument
"names" are?
- Is there a way to enumerate the valid choices for values (e.g. colors
= [red,white,blue])

You might find the "Method Arguments" section on page 332 in the Pickaxe (2nd ed.) helpful, as it describes all the ways you can pass arguments to a method.

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?

   def the_method opts = { :arg => 'default value', :another_arg => 'default value too' }

- How do I handle required vs. optional arguments?

   def the_method opts = { :a => 'default a', :b => 'default b', :c => nil }

     a = opts[:a] || opts['a'] # optional, they pass in nil

     b = opts[:b] || opts['b'] or raise "no b!" # required

- Provide some sort of clue to the calling routines what the argument
"names" are?

   def the_method opts = { :arg => 'default value', :another_arg => 'default value too' }

- Is there a way to enumerate the valid choices for values (e.g. colors
= [red,white,blue])

   def the_method opts = { :a => %w( a b c ).first, :b => %w( d e f ).first }

-a

···

On Thu, 30 Nov 2006, Jason Vogel wrote:
--
if you want others to be happy, practice compassion.
if you want to be happy, practice compassion. -- the dalai lama

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?

  def the_method opts = { :arg => 'default value', :another_arg => 'default value too' }

Not really, at least in 1.8. That sets the default for _opts_, not for each of the named args.

def the_method opts = { :arg => 'default value', :another_arg => 'default value too' }
   p opts
end

the_method :arg => "qwe" # ==> {:arg=>"qwe"}

Note that the hash doesn't retain the default value for :another_arg.

Has this changed in 1.9? Is there a way to set the defaults for keyword args?

...

- Is there a way to enumerate the valid choices for values (e.g. colors
= [red,white,blue])

  def the_method opts = { :a => %w( a b c ).first, :b => %w( d e f ).first }

You know this gets evaluated every time you call the_method, right?

def m opts = { :foo => (puts "called m") }; end
m; m

output:

called m

Anyway, this serves no purpose beyond documentation (it doesn't validate). Why not just put this info into the rdoc for the method?

···

ara.t.howard@noaa.gov wrote:

On Thu, 30 Nov 2006, Jason Vogel wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf wrote:

Okay, I have a couple of questions. If I use the Hash approach,

- How do I handle argument default values?

  def the_method opts = { :arg => 'default value', :another_arg => 'default value too' }

Not really, at least in 1.8. That sets the default for _opts_, not for each of the named args.

This is one way to handle defaults for keyword args:

DEFAULTS = {
   :x => 1,
   :y => 2
}

def m opts = {}
   opts = DEFAULTS.merge(opts)
   p opts
end

m :x => 5 # ==> {:x=>5, :y=>2}

Note that #merge is non-destructive (unlike #update, aka #merge!), so it doesn't affect DEFAULTS.

···

ara.t.howard@noaa.gov wrote:

On Thu, 30 Nov 2006, Jason Vogel wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

In most cases I think it is best if you define DEFAULTS inline, as in:

def m opts = {}
   opts = {:x => 1,
           :y => 2}.merge(opts)
   p opts
end

That way it's closer to the call and thus more self-documenting, and you
don't have to worry about naming a bunch of constants in your class. The
downside is you're newing up a new defaults hash in every method call, and
executing any contained statements.

-RYaN

···

On 11/29/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

Joel VanderWerf wrote:
> ara.t.howard@noaa.gov wrote:
>> On Thu, 30 Nov 2006, Jason Vogel wrote:
>>
>>> Okay, I have a couple of questions. If I use the Hash approach,
>>>
>>> - How do I handle argument default values?
>>
>> def the_method opts = { :arg => 'default value', :another_arg =>
>> 'default value too' }
>
> Not really, at least in 1.8. That sets the default for _opts_, not for
> each of the named args.

This is one way to handle defaults for keyword args:

DEFAULTS = {
   :x => 1,
   :y => 2
}

def m opts = {}
   opts = DEFAULTS.merge(opts)
   p opts
end

m :x => 5 # ==> {:x=>5, :y=>2}

Note that #merge is non-destructive (unlike #update, aka #merge!), so it
doesn't affect DEFAULTS.

--

       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

if you like that style you may like this lib

   http://codeforpeople.com/lib/ruby/parseargs/parseargs-0.3.0/README

   http://rubyforge.org/frs/?group_id=1024&release_id=8211

regards.

-a

···

On Thu, 30 Nov 2006, Ryan Williams wrote:

In most cases I think it is best if you define DEFAULTS inline, as in:

def m opts = {}
opts = {:x => 1,
         :y => 2}.merge(opts)
p opts
end

That way it's closer to the call and thus more self-documenting, and you
don't have to worry about naming a bunch of constants in your class. The
downside is you're newing up a new defaults hash in every method call, and
executing any contained statements.

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

Ryan Williams wrote:

Joel VanderWerf wrote:

...

def m opts = {}
   opts = DEFAULTS.merge(opts)
   p opts
end

m :x => 5 # ==> {:x=>5, :y=>2}

Note that #merge is non-destructive (unlike #update, aka #merge!), so it
doesn't affect DEFAULTS.

In most cases I think it is best if you define DEFAULTS inline, as in:

def m opts = {}
  opts = {:x => 1,
          :y => 2}.merge(opts)
  p opts
end

That way it's closer to the call and thus more self-documenting, and you
don't have to worry about naming a bunch of constants in your class. The
downside is you're newing up a new defaults hash in every method call, and
executing any contained statements.

If you define default option hashes as constants, you can comment them and they will appear in RDOC output. RDoc is even smart enough to try to put the constant value (i.e. the defaults hash) in the doc.

···

On 11/29/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407