|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
I had a bit of a surprise with the following
class Foo def bar(value) @bar = value.upcase end end f = Foo.new my_bar = (f.bar = "bar") I initially thought that my_bar would == "BAR" but in fact it equals "bar". It seems no matter what the final value of the bar= method is the return value is always the parameters. First time I've run into this so I thought I would share and ask if anyone can think of anyway to get around this? Farrel |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
This is on 1.8.6 on Gentoo Linux btw.
|
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On 25/02/2008, Farrel Lifson <farrel.lifson@gmail.com> wrote:
> I had a bit of a surprise with the following > > class Foo > def bar(value) > @bar = value.upcase > end > end And of course the method should be def bar=(value) @bar = value.upcase end |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Mon, Feb 25, 2008 at 07:41:31AM +0900, Farrel Lifson wrote:
> I had a bit of a surprise with the following > > class Foo > def bar(value) > @bar = value.upcase > end > end > > f = Foo.new > my_bar = (f.bar = "bar") > > I initially thought that my_bar would == "BAR" but in fact it equals > "bar". It seems no matter what the final value of the bar= method is > the return value is always the parameters. First time I've run into > this so I thought I would share and ask if anyone can think of anyway > to get around this? > > Farrel > my_bar = f.send(:bar=, "bar") g phil |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Feb 24, 2008, at 2:41 PM, Farrel Lifson wrote: > I had a bit of a surprise with the following > > class Foo > def bar(value) > @bar = value.upcase > end > end > > f = Foo.new > my_bar = (f.bar = "bar") > > I initially thought that my_bar would == "BAR" but in fact it equals > "bar". It seems no matter what the final value of the bar= method is > the return value is always the parameters. First time I've run into > this so I thought I would share and ask if anyone can think of anyway > to get around this? > > Farrel This is just the way ruby works. It *always* returns the right hand side of any method call ending in =. This is for consistency sake. since you can write methods that look like assignment it keeps things consistent to always return the rhs of any assignment. Cheers- - Ezra Zygmuntowicz -- Founder & Software Architect -- ezra@engineyard.com -- EngineYard.com |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
Farrel Lifson wrote:
> I had a bit of a surprise with the following > > class Foo > def bar(value) > @bar = value.upcase > end > end > > f = Foo.new > my_bar = (f.bar = "bar") > > I initially thought that my_bar would == "BAR" but in fact it equals > "bar". It seems no matter what the final value of the bar= method is > the return value is always the parameters. First time I've run into > this so I thought I would share and ask if anyone can think of anyway > to get around this? > > Farrel I'm not sure why the return value of calling bar= is the method argument, but it makes sense to me that the return value is not the *private* instance variable's value. If the return value were the private instance variable's value, that would break the encapsulation that a class is supposed to provide: class Dog def secret_code=(seed) @secret_code = seed * 10 + 2 end end d = Dog.new return_val = (d.secret_code=(3) ) puts return_val #should this reveal the secret code? -- Posted via http://www.ruby-forum.com/. |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
Ezra Zygmuntowicz wrote:
> This is just the way ruby works. It *always* returns the right hand > side of any method call ending in =. This is for consistency sake. Except that it is inconsistent with the usually true, "The return value of a method is the lest expression evaluated." POLS, yada yada yada. Done deal. Whatever it's benefits, though, it adds to list of "This is how Ruby works, except when it doesn't." -- James Britt "The greatest obstacle to discovery is not ignorance, but the illusion of knowledge." - D. Boorstin |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
[Note: parts of this message were removed to make it a legal post.]
On Mon, Feb 25, 2008 at 12:03 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote: > class Dog > def secret_code=(seed) > @secret_code = seed * 10 + 2 > end > end > > d = Dog.new > return_val = (d.secret_code=(3) ) > puts return_val #should this reveal the secret code? > Yes. What would you like it to return? The point is, you're doing d.secret_code = 3 -- you're saying the secret code *is* 3, so actually setting it to something else is a bit misleading, don't you think? class Dog def generate_secret_code(seed) @secret_code = seed * 10 + 2 self end end This has the fun of allowing method chaining; d = Dog.new d.generate_secret_code(3).some_other_method_that_c hains.yet_another(some, args) Arlen |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
[Note: parts of this message were removed to make it a legal post.]
Hold up a second there; Yes. What would you like it to return? The point is, you're doing > d.secret_code = 3 -- you're saying the secret code *is* 3, so actually > setting it to something else is a bit misleading, don't you think? I clearly missed the boat here. I didn't know Ruby always returned the rval of the expression. You learn something new every day. Sorry for biting.Arlen |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
7stud -- said...
> Farrel Lifson wrote: > > I had a bit of a surprise with the following > > > > class Foo > > def bar(value) > > @bar = value.upcase > > end > > end > > > > f = Foo.new > > my_bar = (f.bar = "bar") > > > > I initially thought that my_bar would == "BAR" but in fact it equals > > "bar". It seems no matter what the final value of the bar= method is > > the return value is always the parameters. First time I've run into > > this so I thought I would share and ask if anyone can think of anyway > > to get around this? > > > > Farrel > > I'm not sure why the return value of calling bar= is the method > argument, but it makes sense to me that the return value is not the > *private* instance variable's value. If the return value were the > private instance variable's value, that would break the encapsulation > that a class is supposed to provide: > > class Dog > def secret_code=(seed) > @secret_code = seed * 10 + 2 > end > end > > d = Dog.new > return_val = (d.secret_code=(3) ) > puts return_val #should this reveal the secret code? > I concur; the OP's expected behaviour would break encapsulation. class Foo attr_reader :bar def bar=(value) @bar = value.upcase end end f = Foo.new my_bar = (f.bar = "bar") puts my_bar # "bar" puts f.bar # "BAR" g = Foo.new g.bar = "bar" puts g.bar # "BAR" -- Cheers, Marc |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
Arlen Cuss wrote:
> On Mon, Feb 25, 2008 at 12:03 PM, 7stud -- <bbxx789_05ss@yahoo.com> wrote: > >> class Dog >> def secret_code=(seed) >> @secret_code = seed * 10 + 2 >> end >> end >> >> d = Dog.new >> return_val = (d.secret_code=(3) ) >> puts return_val #should this reveal the secret code? >> > > Yes. What would you like it to return? The point is, you're doing > d.secret_code = 3 -- you're saying the secret code *is* 3, so actually > setting it to something else is a bit misleading, don't you think? Actually, you're saying "Send the message '.secret_code=(3)' to d" It's up to d to decide what that means and what happens next. Suppose secret_code=(x) checks that the given value meets some criteria (say, is a positive int), and if not, uses the value 0. I might want the method to then return a valid value, not simply what was passed in. -- James Britt "We are using here a powerful strategy of synthesis: wishful thinking." - H. Abelson and G. Sussman (in "The Structure and Interpretation of Computer Programs) |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
James Britt wrote:
> Suppose secret_code=(x) checks that the given value meets some criteria > (say, is a positive int), and if not, uses the value 0. I might want > the method to then return a valid value, not simply what was passed in. If the setter is called in an assignment context, the assignment will always return the rhs regardless of what the setter returns. This is for compatibility as Ezra pointed out. If you do: a = b = c = 3 what's the value of a? You would expect it to be 3. What about: a = b.bar = c = 3 What is a now? Again, wouldn't you still be hoping it would be 3? Assignment is a syntactic construct. "b.bar = 3" is not a method call, it's an assignment. Part of evaluating that assignment involves invoking a method, but, by definition, assignment returns the rhs, so whatever happens with any method so invoked, its value is lost. -- Posted via http://www.ruby-forum.com/. |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
On Feb 25, 2008, at 2:09 PM, Mark Bush wrote: > Assignment is a syntactic construct. "b.bar = 3" is not a method > call, > it's an assignment. I would modify that a bit and say that (b.bar = 3) is an assignment expression with a side-effect that happens to be a method call. Consider (a = 3) which is also an assignment expression but with a side-effect of changing the binding of 'a'. So the 'strange' behavior of setter methods comes about because of the context in which they are called, not because they behave differently from other methods. The return value of any method can be discarded in the right context: c = begin a # return value discarded b # return value becomes value of begin/end end Gary Wright |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
Mark Bush wrote:
> James Britt wrote: >> Suppose secret_code=(x) checks that the given value meets some criteria >> (say, is a positive int), and if not, uses the value 0. I might want >> the method to then return a valid value, not simply what was passed in. > > If the setter is called in an assignment context, the assignment will > always return the rhs regardless of what the setter returns. This is > for compatibility as Ezra pointed out. Compatibility with *what*? Not with how other methods behave. It's a cultural thing. > > If you do: > a = b = c = 3 > what's the value of a? You would expect it to be 3. Perhaps. Depends on the language. But let's assume so. > > What about: > a = b.bar = c = 3 > What is a now? Again, wouldn't you still be hoping it would be 3? No. Depends on b. Maybe 3 is not a valid argument for whatever bar does. I expect that if I'm involving an object then that object may have its own ideas about how to handle the request. That's sort of their job. > > Assignment is a syntactic construct. Assignment creates or changes a variable binding. > "b.bar = 3" is not a method call, > it's an assignment. b.methods.include?( 'bar=' ) def b.bar=( arg ) exit if arg % 2 == 0 end Pedantic, sure, but believing that "=" always means a setter method, or is altering an attribute named in the message, is a mistake. It's seems mainly to be a convenience for people who like to think in terms of getters and setters rather than pure messages and private attributes. It's handy, but a little heavy-handed. Here's a less churlish example: def b.bar=(x) @bar = x.to_i.abs end Sadly, this will not return the value of @bar. Most people don't have a problem with this, and I suspect that was a reason matz made Ruby behave this way. But it seems to impede a broader understanding of how Ruby works (and maybe that is part of the reason some folks misuse, for example, open classes.) It's a trade-off. > Part of evaluating that assignment involves > invoking a method, but, by definition, The definition comes first, and can be otherwise. > assignment returns the rhs, so > whatever happens with any method so invoked, its value is lost. As so behaviorally defined in Ruby for methods of a certain form. It breaks the simpler concept of all object interaction being done with messages, and all methods returning the value of the last executed expression. But, again, this is PO(matz)LS. I think I understand why matz choose it, but it was a matter of taste, not immutable laws of computer science. -- James Britt "The use of anthropomorphic terminology when dealing with computing systems is a symptom of professional immaturity." - Edsger W. Dijkstra |
|
![]() |
| Outils de la discussion | |
|
|