[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Subclassing Struct.new

minkoo.seo@gmail.com

2/28/2006 10:56:00 AM

Hi group.

Please have a look at the following:

irb(main):001:0> class F < Struct.new :n
irb(main):002:1> def dec_n
irb(main):003:2> n = n - 1
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> f = F.new 1
=> #<struct F n=1>
irb(main):007:0> f.dec_n
NoMethodError: undefined method `-' for nil:NilClass
from (irb):3:in `dec_n'
from (irb):7
from :0
irb(main):008:0>

I've tried to define a class which decrease n by 1, but failed. How can
I do that?

- Minkoo Seo

36 Answers

chiaro scuro

2/28/2006 11:13:00 AM

0

On 2/28/06, Minkoo Seo <minkoo.seo@gmail.com> wrote:
> Hi group.
>
> Please have a look at the following:

The following works for me. I suspect you should have used self
inside the method

class F < Struct.new(:n)
def dec_n
self.n -= 1
end
end

f = F.new 2
puts f.n == 2

f.dec_n
puts f.n == 1




-- Chiaroscuro --
Liquid Development Blog: http://feeds.feedburner.com/blogspot/liquidd...


minkoo.seo@gmail.com

2/28/2006 11:23:00 AM

0

It works! Thank you.

But, could you tell me why should I have to use self?

- Minkoo Seo

chiaro scuro

2/28/2006 11:46:00 AM

0

On 2/28/06, Minkoo Seo <minkoo.seo@gmail.com> wrote:
> It works! Thank you.
>
> But, could you tell me why should I have to use self?

The alternative would be to use @n, but I am not sure that Struct
organises these properties around individual instance variable. it
probably keeps them in an internal hash, so you have to use the
accessor 'n'. However, when you use it on the left handside you must
prefix with self, otherwise ruby thinks it is a variable n, rather
than a call to the attribute writer 'n='.

I am not sure if this is supposed to be a bug.. it's certainly a
surprising behaviour.

--

-- Chiaroscuro --
Liquid Development Blog: http://feeds.feedburner.com/blogspot/liquidd...


minkoo.seo@gmail.com

2/28/2006 11:58:00 AM

0

chiaro scuro wrote:
> However, when you use it on the left handside you must
> prefix with self, otherwise ruby thinks it is a variable n, rather
> than a call to the attribute writer 'n='.

It is strange because

n=1 is fine, but
n -= 1 is not.

> I am not sure if this is supposed to be a bug.. it's certainly a
> surprising behaviour.

Counter intuitive, at the very least. I really want this behavior to be
fixed.

Best,
Minkoo Seo

Ross Bamford

2/28/2006 12:29:00 PM

0

On Tue, 2006-02-28 at 21:03 +0900, Minkoo Seo wrote:
> chiaro scuro wrote:
> > However, when you use it on the left handside you must
> > prefix with self, otherwise ruby thinks it is a variable n, rather
> > than a call to the attribute writer 'n='.
>
> It is strange because
>
> n=1 is fine, but
> n -= 1 is not.

Well, n = 1 just assigns the fixnum 1 to a (new) local variable 'n'.
n -= 1 is expanded to n = n + 1.

Normally, n + 1 would end up calling your method because Ruby would have
to figure out whether it's a method or variable, but because in this
case Ruby has seen a bare assignment to 'n' by that point, it remembers
that and assumes 'n' is a local variable.

This local variable isn't yet initialized (the n + 1 would be it's
initializer), so n + 1 ends up being nil + 1, or (effectively) nil.+(1),
hence the "undefined method '+' for nil:NilClass".

Using self.n = 1 forces Ruby to treat the assignment as involving the
method 'n' on 'self'.

I don't think it's a bug, but I know it's tripped people (including me)
up before. From the implementation point of view it's probably the
lesser of two evils, though.

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk



minkoo.seo@gmail.com

2/28/2006 12:51:00 PM

0

Ross Bamford wrote:
> Normally, n + 1 would end up calling your method because Ruby would have
> to figure out whether it's a method or variable, but because in this
> case Ruby has seen a bare assignment to 'n' by that point, it remembers
> that and assumes 'n' is a local variable.
>
> This local variable isn't yet initialized (the n + 1 would be it's
> initializer), so n + 1 ends up being nil + 1, or (effectively) nil.+(1),
> hence the "undefined method '+' for nil:NilClass".

Sigh. This reminds me of the rule that I have to use
"this->method_name( )" when I want call a method of T, parent class,
which is passed as template parameter. Anyway, it's not a perfect
world...

Best,
Minkoo Seo

chiaro scuro

2/28/2006 1:14:00 PM

0

On 2/28/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:
> This local variable isn't yet initialized (the n + 1 would be it's
> initializer), so n + 1 ends up being nil + 1, or (effectively) nil.+(1),
> hence the "undefined method '+' for nil:NilClass".
>
> Using self.n = 1 forces Ruby to treat the assignment as involving the
> method 'n' on 'self'.
>
> I don't think it's a bug, but I know it's tripped people (including me)
> up before. From the implementation point of view it's probably the
> lesser of two evils, though.

It's really unrubesque and tricky. What would be the consequences of
handling it as you would normally expect? What would the side effects
be?


--

-- Chiaroscuro --
Liquid Development Blog: http://feeds.feedburner.com/blogspot/liquidd...


Ross Bamford

2/28/2006 1:41:00 PM

0

On Tue, 2006-02-28 at 22:14 +0900, chiaro scuro wrote:
> On 2/28/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:
> > This local variable isn't yet initialized (the n + 1 would be it's
> > initializer), so n + 1 ends up being nil + 1, or (effectively) nil.+(1),
> > hence the "undefined method '+' for nil:NilClass".
> >
> > Using self.n = 1 forces Ruby to treat the assignment as involving the
> > method 'n' on 'self'.
> >
> > I don't think it's a bug, but I know it's tripped people (including me)
> > up before. From the implementation point of view it's probably the
> > lesser of two evils, though.
>
> It's really unrubesque and tricky. What would be the consequences of
> handling it as you would normally expect? What would the side effects
> be?
>

This isn't necessarily based in fact (i.e. I've not surfed the source
just now) but I imagine it would be:

* Harder to parse, with more ambiguous cases.
* Generally slower, since local lookup would be 'the long way'
more often.
* More difficult to follow the code six months down the line
(or on the next guy's screen).

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk



chiaro scuro

2/28/2006 1:45:00 PM

0

On 2/28/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:
> This isn't necessarily based in fact (i.e. I've not surfed the source
> just now) but I imagine it would be:
>
> * Harder to parse, with more ambiguous cases.
> * Generally slower, since local lookup would be 'the long way'
> more often.
> * More difficult to follow the code six months down the line
> (or on the next guy's screen).

I would disagree on the third point.

However, I guess that doing allowing 'selfless' attributes would cause
some worst inconsistency somewhere else. i just wonder what it could
be.

--

-- Chiaroscuro --
Liquid Development Blog: http://feeds.feedburner.com/blogspot/liquidd...


Markus Werner

2/28/2006 1:50:00 PM

0

Hello,


Minkoo Seo wrote:

> Counter intuitive, at the very least. I really want this behavior to be
> fixed.

How should it be in your opinion?

I find it intuitive, cause the sense behind it is obviously.

Ruby assumes that a method call has the current object as receiver.
So it implied the "self." prefix"
But if there is a local var assignment it assumes that you like to use this
local var instead.
Since the local var is determined by the enclosing block it is IMHO an
intuitive solution.

What do you ruby expect to do if it see some think like this?

def foo
a = "hello"
end

Should it assign the local var "a" or should it call the method "a="?
If you say that it should assign the local var "a" just if there is no
method "a=".

What happend to your code if some day in the future you or some else define
a methode "a=" to write the ivar @a. And you don't remember that your
method foo use a local var a?

with kind regards


Markus

PS
What should happend in this case?

def n
@n
end

def n=(n)
@n = n
end