[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Re: Assignment method strangeness

Wilson Bilkovich

12/12/2006 8:17:00 PM

On 12/12/06, Ryan Williams <mr.cruft@gmail.com> wrote:
> Assignment methods are weird, and I wish they acted more like regular
> methods. It seems like they could be, but the parser doesn't properly parse
> the usage. Let me show you what I mean.
>
> Assignment methods can't take more than one argument:
>
> class Test
> def d=(a,b)
> puts "A: #{a}, B: #{b}"
> end
> end
>
> test.d = 1, 2 #=>ArgumentError: wrong number of arguments (1 for 2)
> test.d = [1, 2] #=> ArgumentError: wrong number of arguments (1 for 2)
> test.d = *[1, 2] #=> ArgumentError: wrong number of arguments (1 for 2)
>

Here's what the parse tree looks like for:
test.d = 1
[:attrasgn, [:vcall, :test], :d=, [:array, [:lit, 1]]]

..and for:
test.d = 1,2
[:attrasgn, [:vcall, :test], :d=,
[:array, [:svalue, [:array, [:lit, 1], [:lit, 2]]]]]

As you can see in the first one.. even a single value passed to an
assignment is parsed as an array. If you need multiple arguments to an
assignment, you have to handle them inside the method body itself.

4 Answers

Wilson Bilkovich

12/12/2006 10:37:00 PM

0

On 12/12/06, Ryan Williams <mr.cruft@gmail.com> wrote:
> >
> > As you can see in the first one.. even a single value passed to an
> > assignment is parsed as an array. If you need multiple arguments to an
> > assignment, you have to handle them inside the method body itself.
> >
> >
> You are correct. That's pretty useful, though you still can't pass in
> blocks.
>
> The reason I was interested in this was that I wanted to create some
> attributes that could be assigned either a literal value, or a block that
> returned the literal value when called. Then you could do some really lazy
> evaluation, as in:

Check this out; it may be helpful to you. Pretty similar. It differs
only in where the block is written, but that would be easy to change.

http://www.rubyquiz.com/q...

David Vallner

12/21/2006 11:33:00 AM

0

Citát Ryan Williams <mr.cruft@gmail.com>:
> test.a = { some_other_object.b }
> some_other_object.b = 42
> test.a = 42
>

1. The sheer memory leak of it all. Ruby apparently isn't made to be a good
functional language, even if it's very doable. Also, it looks like a design
smell to me - why can't you use some_other_object.b in the first place, or move
the data into test.a or somewhere else altogether? To me it seems you'd use that
when you can't decide where some data / state actually belongs.

2. Any code where:

foo.bar = baz
foo.bar == baz # => false

makes me want to scream. YMMV. Assignment being a syntactic builtin to the
language with a certain behaviour is a notion too burned into my brain for
juggling the possibility that it isn't to be an option.

David Vallner

David Vallner

12/21/2006 11:35:00 AM

0

One more thing.

Citát Ryan Williams <mr.cruft@gmail.com>:
> test.a = { some_other_object.b }
> some_other_object.b = 42
> test.a = 42
>
> I guess the best route to this is either a new assignment-like method (
> test.set_a) or test.a = Proc.new.
>

I'd be in favour of a method called alias_a. Or make a generic method called as
alias_attribute(:a) {some_other_object.b}

The behaviour you describe to me seems MUCH more related to the builtin method
aliasing than assignment.

David Vallner

Trans

12/21/2006 11:37:00 AM

0


Ryan Williams wrote:
> >
> > As you can see in the first one.. even a single value passed to an
> > assignment is parsed as an array. If you need multiple arguments to an
> > assignment, you have to handle them inside the method body itself.
> >
> >
> You are correct. That's pretty useful, though you still can't pass in
> blocks.
>
> The reason I was interested in this was that I wanted to create some
> attributes that could be assigned either a literal value, or a block that
> returned the literal value when called. Then you could do some really lazy
> evaluation, as in:
>
> test.a = { long_computation }
> ....
> ...in another scope...
> ....
> test.a # returns result of computation
>
> Or you could use it to keep some objects in sync:
>
> test.a = { some_other_object.b }
> some_other_object.b = 42
> test.a = 42
>
> I guess the best route to this is either a new assignment-like method (
> test.set_a) or test.a = Proc.new.

class Test
def a=(x)
case x
when Proc
puts "proc!"
else
puts "value"
end
end
end

test = Test.new
test.a = lamba { some_other_object.b }

also if you do need more than one arg:

def a(x=Exception, y=nil)
return @a if x == Exception
@a = x + y # or whatever
end

t.