[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Simple and stuppid bug (can anyone find it?

paul

12/3/2006 10:33:00 AM

Hi all,
I thought it to be good programming style to make attribute assignment
chainable. When using the attr_writer an assignment returns te value
assigned which is not what I want, so I tried to do-it-myself.
The result is below. This doesn't work. When running Ruby gives:
undefined method 'b=' for "AA":String (NoMethodError)
Anybody, please tell me: *why*. What simple stuppid thing am I
overseeing?
Thanks in advance!
Cheers,
Paul

--the code--
class A
def initialize
end
def a
return @a
end
def a=(someA)
@a = someA
return self
end
def b
return @b
end
def b=(someB)
@b = someB
return self
end
end

puts A.new.a=("AA").b=("BB").a
--the code--

11 Answers

Xavier Noria

12/3/2006 10:53:00 AM

0

On Dec 3, 2006, at 11:35 AM, paul wrote:

> Hi all,
> I thought it to be good programming style to make attribute assignment
> chainable. When using the attr_writer an assignment returns te value
> assigned which is not what I want, so I tried to do-it-myself.
> The result is below. This doesn't work. When running Ruby gives:
> undefined method 'b=' for "AA":String (NoMethodError)
> Anybody, please tell me: *why*. What simple stuppid thing am I
> overseeing?

That is explained on page 85 of the Pickaxe (113 in my PDF edition):

"In older Ruby versions, the result of the assignment was the value
returned by the attribute-setting method. In Ruby 1.8, the value of
the assignment is always the value of the parameter; the return
value of the method is discarded."

-- fxn




David Vallner

12/3/2006 10:54:00 AM

0

paul wrote:
> Hi all,
> I thought it to be good programming style to make attribute assignment
> chainable. When using the attr_writer an assignment returns te value
> assigned which is not what I want, so I tried to do-it-myself.
> The result is below. This doesn't work. When running Ruby gives:
> undefined method 'b=' for "AA":String (NoMethodError)
> Anybody, please tell me: *why*. What simple stuppid thing am I
> overseeing?
> Thanks in advance!
> Cheers,
> Paul
>
> --the code--
> class A
> def initialize
> end
> def a
> return @a
> end
> def a=(someA)
> @a = someA
> return self
> end
> def b
> return @b
> end
> def b=(someB)
> @b = someB
> return self
> end
> end
>
> puts A.new.a=("AA").b=("BB").a
> --the code--
>
>

There is no bug in your code, apparently Ruby always returns the rvalue
from what parses as an assignment.

With your class loaded into irb, I got:

irb(main):039:0> A.new.a=("AA")
=> "AA"

irb(main):043:0> A.new.send('a=', 'AA') # Does what you expected.
=> #<A:0x3b3015c @a="AA">


So, can anyone recall a rationale for the behaviour (consistency with
mainstream programming languages with regards to assignment?) or is this
a Ruby bug?

Either way, disclaimer: I don't like what you're trying to do in the
first place. Pretty much anyone reading your code will expect assignment
to return the rvalue because that's what #attr_writer does, and the
chained assignment in your example just reads plain ugly to me,
especially since I subconsciously parse it as:
A.new.a = "AA".b = "BB".a
i.e. ``assign "BB".a to -both- "AA".b and A.new.a''
and therefore am in favour of consistency with assignment in other
languages instead of consistency with Javaesque property setters (where
the ambiguity doesn't manifest.)

David Vallner

Yukihiro Matsumoto

12/3/2006 11:04:00 AM

0

Hi,

In message "Re: Simple and stuppid bug (can anyone find it?)"
on Sun, 3 Dec 2006 19:53:36 +0900, David Vallner <david@vallner.net> writes:

|So, can anyone recall a rationale for the behaviour (consistency with
|mainstream programming languages with regards to assignment?) or is this
|a Ruby bug?

It's intended behavior. Attribute assignment is assignment (even if
it's implemented by method call). And that's how assignment work for
many languages, including Ruby.

matz.

Martin DeMello

12/3/2006 11:31:00 AM

0

On 12/3/06, paul <pjvleeuwen@gmail.com> wrote:
> Hi all,
> I thought it to be good programming style to make attribute assignment
> chainable. When using the attr_writer an assignment returns te value
> assigned which is not what I want, so I tried to do-it-myself.

If you do want to do this, I'd suggest an attr_setter method, that
generates both foo= and set_foo methods. Then you can chain via

a.set_a(100).set_b(10)

which looks much better than the a.a=(100).b=(10)

martin

paul

12/3/2006 1:52:00 PM

0

:) thanks all for the educating responses. Martin, I really liked you
suggestion.

Let me explain the reason why I did want to chain assignments:
I have a class that has a lot of attributes that can be written at
creation of an instance. To save my typing the whole lot I made a
constructor getting all those attributes. Though, I expect a lot more
attributes in the near future. Since the attributes are not mandatory
for creating the instance using the constructor-method seemed a little
rigid.
My second idea was to use attr_writer to set all the properties, but
chaining seemed saving me some lines (these assignments aren't that
exciting after all).

Is there any moral/principal reason to write:
A.a = "AA"
A.b = "BB"
instead of:
A.set_b("BB").set_a("AA")

?

Cheers,
Paul


Martin DeMello schreef:

> On 12/3/06, paul <pjvleeuwen@gmail.com> wrote:
> > Hi all,
> > I thought it to be good programming style to make attribute assignment
> > chainable. When using the attr_writer an assignment returns te value
> > assigned which is not what I want, so I tried to do-it-myself.
>
> If you do want to do this, I'd suggest an attr_setter method, that
> generates both foo= and set_foo methods. Then you can chain via
>
> a.set_a(100).set_b(10)
>
> which looks much better than the a.a=(100).b=(10)
>
> martin

dblack

12/3/2006 2:06:00 PM

0

Martin DeMello

12/3/2006 3:13:00 PM

0

On 12/3/06, paul <pjvleeuwen@gmail.com> wrote:
> :) thanks all for the educating responses. Martin, I really liked you
> suggestion.
>
>
> Is there any moral/principal reason to write:
> A.a = "AA"
> A.b = "BB"
> instead of:
> A.set_b("BB").set_a("AA")

Actually, when I have this problem, I tend to use a third option:

class A
def initialize(args)
set args
end

def set(arg_hash)
arg_hash.each_pair {|k, v|
self.send(:"#{k}=", v)
}
self
end
end

Now you can do a = A.new(:foo => "hello", :bar => "world").whatever
(assuming, of course, that you have appropriately called attr_writer
:foo, :bar or otherwise defined #foo= and #bar= first).

If you only want to set the instance variables when you create the
object, you can get rid of set and inline the code into initialize
instead.

martin

David Vallner

12/3/2006 4:19:00 PM

0

paul wrote:
> My second idea was to use attr_writer to set all the properties, but
> chaining seemed saving me some lines (these assignments aren't that
> exciting after all).
>

Either way, I don't agree with the motivation, it's very easy to lose
track of what you've assigned to in a method chain as an extension of
the fact any method chain is a detriment to readability if the steps
aren't trivial (e.g. require keeping in your head what the previous step
returned).

Personally, I'd go with the options hash Martin DeMello proposed. It's
rather idiomatic, easier to read (a bit) than a method chain since
initialisation logic is kept in the call to #new, and doesn't involve
superfluous typing.

David Vallner

Mike Durham

12/4/2006 8:27:00 AM

0

David Vallner wrote:
> paul wrote:
>> My second idea was to use attr_writer to set all the properties, but
>> chaining seemed saving me some lines (these assignments aren't that
>> exciting after all).
>>
>
> Either way, I don't agree with the motivation, it's very easy to lose
> track of what you've assigned to in a method chain as an extension of
> the fact any method chain is a detriment to readability if the steps
> aren't trivial (e.g. require keeping in your head what the previous step
> returned).
>
> Personally, I'd go with the options hash Martin DeMello proposed. It's
> rather idiomatic, easier to read (a bit) than a method chain since
> initialisation logic is kept in the call to #new, and doesn't involve
> superfluous typing.
>
> David Vallner
>
In my opinion, if I understood the problem correctly, if a
function/method ends with a 'return self (or whatever)' then that's what
should be returned. There is no acceptable excuse for nor returning it.
Cheers, Mike

paul

12/6/2006 12:12:00 PM

0

:) you would expect it yes :) (I did)
Without the help of the guy's here I would have probably taken a while
to figure it out myself.
It's clear for me now. The new rule, written into my brain: methodes
whose names end in '=' always return the first argument. Writing this
down made me think: with multiple arguments, does it return them all,
or just the first. I gave it a try, and it seems like I'm not allowed
to give more then one argument to an methodes whose names end in '='.

Can anyone confirm this as a rule?

irb(main):001:0> class A
irb(main):002:1> def a=(b)
irb(main):003:2> puts 'in a=(b)'
irb(main):004:2> @a = b
irb(main):005:2> return 'c'
irb(main):006:2> end
irb(main):007:1> def a
irb(main):008:2> return a
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> aa = A.new
=> #<A:0x2c1067c>
irb(main):012:0> aa.a = 'b'
in a=(b)
=> "b"
irb(main):013:0> class X
irb(main):014:1> def x=(y, z)
irb(main):015:2> puts 'in x=(y, z)'
irb(main):016:2> @x = [y, z]
irb(main):017:2> return 'w'
irb(main):018:2> end
irb(main):019:1> def x
irb(main):020:2> return @x
irb(main):021:2> end
irb(main):022:1> end
=> nil
irb(main):023:0> xx = X.new
=> #<X:0x2bfd194>
irb(main):024:0> xx.x=('y', 'z')
SyntaxError: compile error
(irb):24: syntax error
xx.x=('y', 'z')
^
from (irb):24
irb(main):025:0>