From: Robert Klemme Date: 2004-05-01T20:54:01+09:00 Subject: Re: def [](v) xx; return yy; end # returned value is ignored !? "Jean-Hugues ROBERT" schrieb im Newsbeitrag news:6.0.1.1.0.20040430224610.01cde668@pop.mail.yahoo.com... > At 05:40 01/05/2004 +0900, you wrote: > > >On Apr 30, 2004, at 11:58 AM, Jean-Hugues ROBERT wrote: > > > >>At 01:49 01/05/2004 +0900, you wrote: > >>>"Jean-Hugues ROBERT" schrieb im Newsbeitrag > >>>news:6.0.1.1.0.20040430083010.01ce4ab8@pop.mail.yahoo.com... > >>> > Hi, > >>> > > >>> > For some class I am redefining operator []=(x). Works great. > >>> > > >>> > However when I use it, p xx[] = zz prints zz, not the value > >>> > returned by my method. It makes some sense yet I would have > >>> > thought that the responsibility for that should belong to > >>> > my method. Am I missing something ? > >>> > >>>Yes, it's defined that way (see below). > >> > >>Humm, things are the way they are. When I get annoyed by my > >>kinds questions I end up answering "that's because it's been > >>that way for billion years". I am there quoting the E.T. answer > >>in movie Contact by Robert Zemeckis. > > > >It wasn't always that way. Calling "Foo.bar = value" used to respect > >#bar='s return value. Later, it was decided by matz that consistancy was > >best, and the behavior was changed to be consistant with the behavior of > >the normal assignment operator. > > > >One reason for this is that people would tend to expect this behavior, and > >perhaps not think about return values when writing the functions. So the > >following code might not do what is expected. > > > >class Foo > > def bar=(val) > > @bar = val.to_i > > end > >end > > > >f = Foo.new > >g = f.bar = h = "23" > > > >In this case, you would probably expect g, h and f.bar to have been > >assigned the same way. If the return value of #bar= is respected, however, > >h and g would have different values. > > > >cheers, > >--Mark > > That makes sense. Yet, I am missing the xxx= where I do control the value > assigned to the lvalue. Well, you can get close by using the same approach that OpenStruct uses: you need an instance to host all variables and then you can fully control the behavior of assignment. A simple example: class Scope def method_missing(sym, *args) str = sym.to_s case str when /^(.+)=$/ define_member($1) else raise ArgumentError unless args.empty? define_member(str) end send(sym, *args) end def define_member(name) eval "def self.#{name}=(x);@#{name}=x;end" eval "def self.#{name}();@#{name};end" end end irb(main):058:0> env = Scope.new => # irb(main):059:0> env.x => nil irb(main):060:0> env.x=100 => 100 irb(main):061:0> env.y="foo" => "foo" irb(main):062:0> env.y => "foo" irb(main):063:0> env => # Now you can modify those methods that are defined as accessors in define_member() in any way you like and thus control the value assigned. It's not the full integration into the language that you are looking for, but it might come close enough. The problem is that to achieve what you want the language would need to be radically changed and I don't think it's a good idea to allow for global redefinition of =. That could wreak too much havoc on existing code. Btw, by adding: class Scope def with(&b) instance_eval &b end end You can use variables that you have defined already quite naturally: irb(main):034:0> env.x=10 => 10 irb(main):035:0> env.with { p x; x = 20; p x; p self }# 10 20 # => nil > I am not alone. At this point there are multiple known cases where it would > be needed for transparency: > - Reference, a reference is an indirect mean of access to a lvalue's > value that is dereferenced when the value is needed and that also makes it > possible to assign a value to the lvalue at any time. > - Lazy, a Lazy is a value that is computed when it is needed, not before. You don't necessarily need references for that. Typically it is used as a member and you can do it this way: class Foo def lazy=(x);@lazy=x;end def lazy if @lazy.nil? @lazy = compute_lazy() end @lazy end end You can even automate that by providing blocks that do the initialization calculation. > - Future, a Future is the returned value of an asynchronous method call > that is waited for when it is needed, not before. > - LogicVariable, a LogicVariable is a variable that can be free in > addition to being bound to some value as regular variables are. IMHO there are lots of ways to do what you want in Ruby, only the exact way you want is not possible. Sometimes it's better to step back and open one's mind for other solutions. As I suggested before, a Hash can pretty much do what you want - it just doesn't give you the exact syntactic sugar you want. env = Hash.new do |h,key| # do whatever is needed to calculate the value of key end env[ :x ] = true env[ :y ] = false env[ :x ] && env[ :y ] .... Or, with the example above: env.x=true env.y=false env.x && env.y .... Regards robert