Ruby's attr_accessor vs setter method vs local variable [duplicate] - ruby

Ruby setters—whether created by (c)attr_accessor or manually—seem to be the only methods that need self. qualification when accessed within the class itself. This seems to put Ruby alone the world of languages:
All methods need self/this (like Perl, and I think Javascript)
No methods require self/this is (C#, Java)
Only setters need self/this (Ruby?)
The best comparison is C# vs Ruby, because both languages support accessor methods which work syntactically just like class instance variables: foo.x = y, y = foo.x . C# calls them properties.
Here's a simple example; the same program in Ruby then C#:
class A
def qwerty; #q; end # manual getter
def qwerty=(value); #q = value; end # manual setter, but attr_accessor is same
def asdf; self.qwerty = 4; end # "self." is necessary in ruby?
def xxx; asdf; end # we can invoke nonsetters w/o "self."
def dump; puts "qwerty = #{qwerty}"; end
end
a = A.new
a.xxx
a.dump
take away the self.qwerty =() and it fails (Ruby 1.8.6 on Linux & OS X). Now C#:
using System;
public class A {
public A() {}
int q;
public int qwerty {
get { return q; }
set { q = value; }
}
public void asdf() { qwerty = 4; } // C# setters work w/o "this."
public void xxx() { asdf(); } // are just like other methods
public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}
public class Test {
public static void Main() {
A a = new A();
a.xxx();
a.dump();
}
}
Question: Is this true? Are there other occasions besides setters where self is necessary? I.e., are there other occasions where a Ruby method cannot be invoked without self?
There are certainly lots of cases where self becomes necessary. This is not unique to Ruby, just to be clear:
using System;
public class A {
public A() {}
public int test { get { return 4; }}
public int useVariable() {
int test = 5;
return test;
}
public int useMethod() {
int test = 5;
return this.test;
}
}
public class Test {
public static void Main() {
A a = new A();
Console.WriteLine("{0}", a.useVariable()); // prints 5
Console.WriteLine("{0}", a.useMethod()); // prints 4
}
}
Same ambiguity is resolved in same way. But while subtle I'm asking about the case where
A method has been defined, and
No local variable has been defined, and
we encounter
qwerty = 4
which is ambiguous—is this a method invocation or an new local variable assignment?
#Mike Stone
Hi! I understand and appreciate the points you've made and your
example was great. Believe me when I say, if I had enough reputation,
I'd vote up your response. Yet we still disagree:
on a matter of semantics, and
on a central point of fact
First I claim, not without irony, we're having a semantic debate about the
meaning of 'ambiguity'.
When it comes to parsing and programming language semantics (the subject
of this question), surely you would admit a broad spectrum of the notion
'ambiguity'. Let's just adopt some random notation:
ambiguous: lexical ambiguity (lex must 'look ahead')
Ambiguous: grammatical ambiguity (yacc must defer to parse-tree analysis)
AMBIGUOUS: ambiguity knowing everything at the moment of execution
(and there's junk between 2-3 too). All these categories are resolved by
gathering more contextual info, looking more and more globally. So when you
say,
"qwerty = 4" is UNAMBIGUOUS in C#
when there is no variable defined...
I couldn't agree more. But by the same token, I'm saying
"qwerty = 4" is un-Ambiguous in ruby
(as it now exists)
"qwerty = 4" is Ambiguous in C#
And we're not yet contradicting each other. Finally, here's where we really
disagree: Either ruby could or could not be implemented without any further
language constructs such that,
For "qwerty = 4," ruby UNAMBIGUOUSLY
invokes an existing setter if there
is no local variable defined
You say no. I say yes; another ruby could exist which behaves exactly like
the current in every respect, except "qwerty = 4" defines a new
variable when no setter and no local exists, it invokes the setter if one
exists, and it assigns to the local if one exists. I fully accept that I
could be wrong. In fact, a reason why I might be wrong would be interesting.
Let me explain.
Imagine you are writing a new OO language with accessor methods looking
like instances vars (like ruby & C#). You'd probably start with
conceptual grammars something like:
var = expr // assignment
method = expr // setter method invocation
But the parser-compiler (not even the runtime) will puke, because even after
all the input is grokked there's no way to know which grammar is pertinent.
You're faced which a classic choice. I can't be sure of the details, but
basically ruby does this:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
that is why it's un-Ambiguous, while and C# does this:
symbol = expr // push 'symbol=' onto parse tree and decide later
// if local variable is def'd somewhere in scope: assignment
// else if a setter is def'd in scope: invocation
For C#, 'later' is still at compile time.
I'm sure ruby could do the same, but 'later' would have to be at runtime, because
as ben points out you don't know until the statement is executed which case
applies.
My question was never intended to mean "do I really need the 'self.'?" or "what
potential ambiguity is being avoided?" Rather I wanted to know why was this
particular choice made? Maybe it's not performance. Maybe it just got the job
done, or it was considered best to always allow a 1-liner local to override a
method (a pretty rare case requirement) ...
But I'm sort of suggesting that the most dynamical language might be the one which
postpones this decision the longest, and chooses semantics based on the most contextual
info: so if you have no local and you defined a setter, it would use the setter. Isn't
this why we like ruby, smalltalk, objc, because method invocation is decided at runtime,
offering maximum expressiveness?

Well, I think the reason this is the case is because qwerty = 4 is ambiguous—are you defining a new variable called qwerty or calling the setter? Ruby resolves this ambiguity by saying it will create a new variable, thus the self. is required.
Here is another case where you need self.:
class A
def test
4
end
def use_variable
test = 5
test
end
def use_method
test = 5
self.test
end
end
a = A.new
a.use_variable # returns 5
a.use_method # returns 4
As you can see, the access to test is ambiguous, so the self. is required.
Also, this is why the C# example is actually not a good comparison, because you define variables in a way that is unambiguous from using the setter. If you had defined a variable in C# that was the same name as the accessor, you would need to qualify calls to the accessor with this., just like the Ruby case.

The important thing to remember here is that Ruby methods can be (un)defined at any point, so to intelligently resolve the ambiguity, every assignment would need to run code to check whether there is a method with the assigned-to name at the time of assignment.

Because otherwise it would be impossible to set local variables at all inside of methods. variable = some_value is ambiguous. For example:
class ExampleClass
attr_reader :last_set
def method_missing(name, *args)
if name.to_s =~ /=$/
#last_set = args.first
else
super
end
end
def some_method
some_variable = 5 # Set a local variable? Or call method_missing?
puts some_variable
end
end
If self wasn't required for setters, some_method would raise NameError: undefined local variable or method 'some_variable'. As-is though, the method works as intended:
example = ExampleClass.new
example.blah = 'Some text'
example.last_set #=> "Some text"
example.some_method # prints "5"
example.last_set #=> "Some text"

Related

Setting an instance variable with `attr_accessor` in a constructor leads to a `nil` value when accessed outside the class [duplicate]

Ruby setters—whether created by (c)attr_accessor or manually—seem to be the only methods that need self. qualification when accessed within the class itself. This seems to put Ruby alone the world of languages:
All methods need self/this (like Perl, and I think Javascript)
No methods require self/this is (C#, Java)
Only setters need self/this (Ruby?)
The best comparison is C# vs Ruby, because both languages support accessor methods which work syntactically just like class instance variables: foo.x = y, y = foo.x . C# calls them properties.
Here's a simple example; the same program in Ruby then C#:
class A
def qwerty; #q; end # manual getter
def qwerty=(value); #q = value; end # manual setter, but attr_accessor is same
def asdf; self.qwerty = 4; end # "self." is necessary in ruby?
def xxx; asdf; end # we can invoke nonsetters w/o "self."
def dump; puts "qwerty = #{qwerty}"; end
end
a = A.new
a.xxx
a.dump
take away the self.qwerty =() and it fails (Ruby 1.8.6 on Linux & OS X). Now C#:
using System;
public class A {
public A() {}
int q;
public int qwerty {
get { return q; }
set { q = value; }
}
public void asdf() { qwerty = 4; } // C# setters work w/o "this."
public void xxx() { asdf(); } // are just like other methods
public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}
public class Test {
public static void Main() {
A a = new A();
a.xxx();
a.dump();
}
}
Question: Is this true? Are there other occasions besides setters where self is necessary? I.e., are there other occasions where a Ruby method cannot be invoked without self?
There are certainly lots of cases where self becomes necessary. This is not unique to Ruby, just to be clear:
using System;
public class A {
public A() {}
public int test { get { return 4; }}
public int useVariable() {
int test = 5;
return test;
}
public int useMethod() {
int test = 5;
return this.test;
}
}
public class Test {
public static void Main() {
A a = new A();
Console.WriteLine("{0}", a.useVariable()); // prints 5
Console.WriteLine("{0}", a.useMethod()); // prints 4
}
}
Same ambiguity is resolved in same way. But while subtle I'm asking about the case where
A method has been defined, and
No local variable has been defined, and
we encounter
qwerty = 4
which is ambiguous—is this a method invocation or an new local variable assignment?
#Mike Stone
Hi! I understand and appreciate the points you've made and your
example was great. Believe me when I say, if I had enough reputation,
I'd vote up your response. Yet we still disagree:
on a matter of semantics, and
on a central point of fact
First I claim, not without irony, we're having a semantic debate about the
meaning of 'ambiguity'.
When it comes to parsing and programming language semantics (the subject
of this question), surely you would admit a broad spectrum of the notion
'ambiguity'. Let's just adopt some random notation:
ambiguous: lexical ambiguity (lex must 'look ahead')
Ambiguous: grammatical ambiguity (yacc must defer to parse-tree analysis)
AMBIGUOUS: ambiguity knowing everything at the moment of execution
(and there's junk between 2-3 too). All these categories are resolved by
gathering more contextual info, looking more and more globally. So when you
say,
"qwerty = 4" is UNAMBIGUOUS in C#
when there is no variable defined...
I couldn't agree more. But by the same token, I'm saying
"qwerty = 4" is un-Ambiguous in ruby
(as it now exists)
"qwerty = 4" is Ambiguous in C#
And we're not yet contradicting each other. Finally, here's where we really
disagree: Either ruby could or could not be implemented without any further
language constructs such that,
For "qwerty = 4," ruby UNAMBIGUOUSLY
invokes an existing setter if there
is no local variable defined
You say no. I say yes; another ruby could exist which behaves exactly like
the current in every respect, except "qwerty = 4" defines a new
variable when no setter and no local exists, it invokes the setter if one
exists, and it assigns to the local if one exists. I fully accept that I
could be wrong. In fact, a reason why I might be wrong would be interesting.
Let me explain.
Imagine you are writing a new OO language with accessor methods looking
like instances vars (like ruby & C#). You'd probably start with
conceptual grammars something like:
var = expr // assignment
method = expr // setter method invocation
But the parser-compiler (not even the runtime) will puke, because even after
all the input is grokked there's no way to know which grammar is pertinent.
You're faced which a classic choice. I can't be sure of the details, but
basically ruby does this:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
that is why it's un-Ambiguous, while and C# does this:
symbol = expr // push 'symbol=' onto parse tree and decide later
// if local variable is def'd somewhere in scope: assignment
// else if a setter is def'd in scope: invocation
For C#, 'later' is still at compile time.
I'm sure ruby could do the same, but 'later' would have to be at runtime, because
as ben points out you don't know until the statement is executed which case
applies.
My question was never intended to mean "do I really need the 'self.'?" or "what
potential ambiguity is being avoided?" Rather I wanted to know why was this
particular choice made? Maybe it's not performance. Maybe it just got the job
done, or it was considered best to always allow a 1-liner local to override a
method (a pretty rare case requirement) ...
But I'm sort of suggesting that the most dynamical language might be the one which
postpones this decision the longest, and chooses semantics based on the most contextual
info: so if you have no local and you defined a setter, it would use the setter. Isn't
this why we like ruby, smalltalk, objc, because method invocation is decided at runtime,
offering maximum expressiveness?
Well, I think the reason this is the case is because qwerty = 4 is ambiguous—are you defining a new variable called qwerty or calling the setter? Ruby resolves this ambiguity by saying it will create a new variable, thus the self. is required.
Here is another case where you need self.:
class A
def test
4
end
def use_variable
test = 5
test
end
def use_method
test = 5
self.test
end
end
a = A.new
a.use_variable # returns 5
a.use_method # returns 4
As you can see, the access to test is ambiguous, so the self. is required.
Also, this is why the C# example is actually not a good comparison, because you define variables in a way that is unambiguous from using the setter. If you had defined a variable in C# that was the same name as the accessor, you would need to qualify calls to the accessor with this., just like the Ruby case.
The important thing to remember here is that Ruby methods can be (un)defined at any point, so to intelligently resolve the ambiguity, every assignment would need to run code to check whether there is a method with the assigned-to name at the time of assignment.
Because otherwise it would be impossible to set local variables at all inside of methods. variable = some_value is ambiguous. For example:
class ExampleClass
attr_reader :last_set
def method_missing(name, *args)
if name.to_s =~ /=$/
#last_set = args.first
else
super
end
end
def some_method
some_variable = 5 # Set a local variable? Or call method_missing?
puts some_variable
end
end
If self wasn't required for setters, some_method would raise NameError: undefined local variable or method 'some_variable'. As-is though, the method works as intended:
example = ExampleClass.new
example.blah = 'Some text'
example.last_set #=> "Some text"
example.some_method # prints "5"
example.last_set #=> "Some text"

How can I compare classes in Ruby?

How can I compare classes in Ruby or in other words how can I translate this Java code into Ruby?
Class<?> clazz = ...;
if (clazz == String.class) {
...
} else if (clazz == Integer.class) {
...
}
To clarify: I do not want to compare object instances or check if an object is an instance of a class.
EDIT: I do not want to compare object instances or check if an object is an instance of a class, i.e. is_a? and kind_of? don't help me.
The literal translation of your Java code would be something like
klass = ...
if klass == String
...
elsif klass == Integer
...
end
Or, more idiomatically
klass = ...
case
when klass == String
...
when klass == Integer
...
end
Or maybe
klass = ...
DISPATCH_TABLE = {
String => -> { ... },
Integer => -> { ... }
}
DISPATCH_TABLE[klass].()
However, Ruby is an object-oriented language, and in an object-oriented language this simply doesn't make sense. You would instead just write
class String
def do_something
...
end
end
class Integer
def do_something
...
end
end
and the language will perform the dispatching for you. This is called polymorphism and is supported by pretty much every object-oriented language and many non-object-oriented ones as well.
This particular transformation is one of the fundamental Refactorings described in Martin Fowler's book (p. 255), it is called the Replace Conditional With Polymorphism Refactoring.
The biggest problem with providing a sensible solution to your problem is that you don't tell us what the problem is. You only tell us what the solution is. Or, more precisely, you tell us what you think the solution is in Java, and you somehow expect that the solution in Ruby would be exactly 100% identical, even though the languages couldn't be more different.
To provide a good solution, we need to know the problem first. In other words: the most relevant parts of your question are the …s
>> "foo".class == "bar".class
true
In Ruby, all classes objects are instances of the Class class. The names of classes are constants that refer to the instance. If you have a reference to the class object, you can compare it with the named constant for that class. So you could do:
if klass == String
...
elsif klass == Integer
...
end
The expression String.class == Integer.class would be true, since the class of both classes is, of course, Class.

What's the equivalent to "method reference" in Ruby

for instance in python it is possible to assign a method to a variable:
class MyClass
def myMethod(self):
return "Hi"
x = MyClass()
method = x.myMethod
print method() # prints Hi
I know this should be possible in Ruby, but I don't know what's the syntax.
You need to grab the method by using method with the method’s name as an argument. This will return you an instance of type Method, which can be called with call().
class MyClass
def myMethod
"Hi"
end
end
x = MyClass.new
m = x.method(:myMethod)
# => #<Method: MyClass#myMethod>
puts m.call
# You can also do m[] instead of m.call()
Note that any arguments would need to be added to the call method.
In many practical cases, however, there is no need to have the method itself saved to a variable in Ruby; if you just want to dynamically call a method (i.e. send a message to an object) and there is no need to save the method, you could also use the send (or __send__ method in case of name clashes).
x = MyClass.new
puts x.send :myMethod # also possible with a string: m.send "myMethod"
# "Hi"
Any arguments should follow the method name:
puts x.send(:myMethod, arg1, arg2)
To use it like this is probably more Ruby-like, as the concept of Method classes is not as prominent as it is in Python. In Python, you can always think of a two step mechanism when doing something like a_string.split(); first you grab the method with a_string.split and then you call it (either implicitly with () or explicitly with __call__()). So, cutting that two-step mechanism is rather natural to do.
Ruby is more based on message passing and to actually get a method class in Ruby, you’ll have to do some more work, because in some way, the method object will have to be constructed for you at that point. So, unless you really need some Methods object in Ruby, you should rather stick to the message passing abstraction and simply use send.
I think you are looking for Proc or lambda block
x = Proc.new { return "Hello World" }
puts x.call
x = lambda { return "Hello World" }
puts x.call
I would read this short post - there is a slight but significant difference in the way the methods behave
http://samdanielson.com/2007/3/19/proc-new-vs-lambda-in-ruby

Is it possible to compare private attributes in Ruby?

I'm thinking in:
class X
def new()
#a = 1
end
def m( other )
#a == other.#a
end
end
x = X.new()
y = X.new()
x.m( y )
But it doesn't works.
The error message is:
syntax error, unexpected tIVAR
How can I compare two private attributes from the same class then?
There have already been several good answers to your immediate problem, but I have noticed some other pieces of your code that warrant a comment. (Most of them trivial, though.)
Here's four trivial ones, all of them related to coding style:
Indentation: you are mixing 4 spaces for indentation and 5 spaces. It is generally better to stick to just one style of indentation, and in Ruby that is generally 2 spaces.
If a method doesn't take any parameters, it is customary to leave off the parantheses in the method definition.
Likewise, if you send a message without arguments, the parantheses are left off.
No whitespace after an opening paranthesis and before a closing one, except in blocks.
Anyway, that's just the small stuff. The big stuff is this:
def new
#a = 1
end
This does not do what you think it does! This defines an instance method called X#new and not a class method called X.new!
What you are calling here:
x = X.new
is a class method called new, which you have inherited from the Class class. So, you never call your new method, which means #a = 1 never gets executed, which means #a is always undefined, which means it will always evaluate to nil which means the #a of self and the #a of other will always be the same which means m will always be true!
What you probably want to do is provide a constructor, except Ruby doesn't have constructors. Ruby only uses factory methods.
The method you really wanted to override is the instance method initialize. Now you are probably asking yourself: "why do I have to override an instance method called initialize when I'm actually calling a class method called new?"
Well, object construction in Ruby works like this: object construction is split into two phases, allocation and initialization. Allocation is done by a public class method called allocate, which is defined as an instance method of class Class and is generally never overriden. It just allocates the memory space for the object and sets up a few pointers, however, the object is not really usable at this point.
That's where the initializer comes in: it is an instance method called initialize, which sets up the object's internal state and brings it into a consistent, fully defined state which can be used by other objects.
So, in order to fully create a new object, what you need to do is this:
x = X.allocate
x.initialize
[Note: Objective-C programmers may recognize this.]
However, because it is too easy to forget to call initialize and as a general rule an object should be fully valid after construction, there is a convenience factory method called Class#new, which does all that work for you and looks something like this:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[Note: actually, initialize is private, so reflection has to be used to circumvent the access restrictions like this: obj.send(:initialize, *args, &block)]
Lastly, let me explain what's going wrong in your m method. (The others have already explained how to solve it.)
In Ruby, there is no way (note: in Ruby, "there is no way" actually translates to "there is always a way involving reflection") to access an instance variable from outside the instance. That's why it's called an instance variable after all, because it belongs to the instance. This is a legacy from Smalltalk: in Smalltalk there are no visibility restrictions, all methods are public. Thus, instance variables are the only way to do encapsulation in Smalltalk, and, after all, encapsulation is one of the pillars of OO. In Ruby, there are visibility restrictions (as we have seen above, for example), so it is not strictly necessary to hide instance variables for that reason. There is another reason, however: the Uniform Access Principle.
The UAP states that how to use a feature should be independent from how the feature is implemented. So, accessing a feature should always be the same, i.e. uniform. The reason for this is that the author of the feature is free to change how the feature works internally, without breaking the users of the feature. In other words, it's basic modularity.
This means for example that getting the size of a collection should always be the same, regardless of whether the size is stored in a variable, computed dynamically every time, lazily computed the first time and then stored in a variable, memoized or whatever. Sounds obvious, but e.g. Java gets this wrong:
obj.size # stored in a field
vs.
obj.getSize() # computed
Ruby takes the easy way out. In Ruby, there is only one way to use a feature: sending a message. Since there is only one way, access is trivially uniform.
So, to make a long story short: you simply can't access another instance's instance variable. you can only interact with that instance via message sending. Which means that the other object has to either provide you with a method (in this case at least of protected visibility) to access its instance variable, or you have to violate that object's encapsulation (and thus lose Uniform Access, increase coupling and risk future breakage) by using reflection (in this case instance_variable_get).
Here it is, in all its glory:
#!/usr/bin/env ruby
class X
def initialize(a=1)
#a = a
end
def m(other)
#a == other.a
end
protected
attr_reader :a
end
require 'test/unit'
class TestX < Test::Unit::TestCase
def test_that_m_evaluates_to_true_when_passed_two_empty_xs
x, y = X.new, X.new
assert x.m(y)
end
def test_that_m_evaluates_to_true_when_passed_two_xs_with_equal_attributes
assert X.new('foo').m(X.new('foo'))
end
end
Or alternatively:
class X
def m(other)
#a == other.instance_variable_get(:#a)
end
end
Which one of those two you chose is a matter of personly taste, I would say. The Set class in the standard library uses the reflection version, although it uses instance_eval instead:
class X
def m(other)
#a == other.instance_eval { #a }
end
end
(I have no idea why. Maybe instance_variable_get simply didn't exist when Set was written. Ruby is going to be 17 years old in February, some of the stuff in the stdlib is from the very early days.)
There are several methods
Getter:
class X
attr_reader :a
def m( other )
a == other.a
end
end
instance_eval:
class X
def m( other )
#a == other.instance_eval { #a }
end
end
instance_variable_get:
class X
def m( other )
#a == other.instance_variable_get :#a
end
end
I don't think ruby has a concept of "friend" or "protected" access, and even "private" is easily hacked around. Using a getter creates a read-only property, and instance_eval means you have to know the name of the instance variable, so the connotation is similar.
If you don't use the instance_eval option (as #jleedev posted), and choose to use a getter method, you can still keep it protected
If you want a protected method in Ruby, just do the following to create a getter that can only be read from objects of the same class:
class X
def new()
#a = 1
end
def m( other )
#a == other.a
end
protected
def a
#a
end
end
x = X.new()
y = X.new()
x.m( y ) # Returns true
x.a # Throws error
Not sure, but this might help:
Outside of the class, it's a little bit harder:
# Doesn't work:
irb -> a.#foo
SyntaxError: compile error
(irb):9: syntax error, unexpected tIVAR
from (irb):9
# But you can access it this way:
irb -> a.instance_variable_get(:#foo)
=> []
http://whynotwiki.com/Ruby_/_Variables_and_constants#Variable_scope.2Faccessibility

Why do Ruby setters need "self." qualification within the class?

Ruby setters—whether created by (c)attr_accessor or manually—seem to be the only methods that need self. qualification when accessed within the class itself. This seems to put Ruby alone the world of languages:
All methods need self/this (like Perl, and I think Javascript)
No methods require self/this is (C#, Java)
Only setters need self/this (Ruby?)
The best comparison is C# vs Ruby, because both languages support accessor methods which work syntactically just like class instance variables: foo.x = y, y = foo.x . C# calls them properties.
Here's a simple example; the same program in Ruby then C#:
class A
def qwerty; #q; end # manual getter
def qwerty=(value); #q = value; end # manual setter, but attr_accessor is same
def asdf; self.qwerty = 4; end # "self." is necessary in ruby?
def xxx; asdf; end # we can invoke nonsetters w/o "self."
def dump; puts "qwerty = #{qwerty}"; end
end
a = A.new
a.xxx
a.dump
take away the self.qwerty =() and it fails (Ruby 1.8.6 on Linux & OS X). Now C#:
using System;
public class A {
public A() {}
int q;
public int qwerty {
get { return q; }
set { q = value; }
}
public void asdf() { qwerty = 4; } // C# setters work w/o "this."
public void xxx() { asdf(); } // are just like other methods
public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}
public class Test {
public static void Main() {
A a = new A();
a.xxx();
a.dump();
}
}
Question: Is this true? Are there other occasions besides setters where self is necessary? I.e., are there other occasions where a Ruby method cannot be invoked without self?
There are certainly lots of cases where self becomes necessary. This is not unique to Ruby, just to be clear:
using System;
public class A {
public A() {}
public int test { get { return 4; }}
public int useVariable() {
int test = 5;
return test;
}
public int useMethod() {
int test = 5;
return this.test;
}
}
public class Test {
public static void Main() {
A a = new A();
Console.WriteLine("{0}", a.useVariable()); // prints 5
Console.WriteLine("{0}", a.useMethod()); // prints 4
}
}
Same ambiguity is resolved in same way. But while subtle I'm asking about the case where
A method has been defined, and
No local variable has been defined, and
we encounter
qwerty = 4
which is ambiguous—is this a method invocation or an new local variable assignment?
#Mike Stone
Hi! I understand and appreciate the points you've made and your
example was great. Believe me when I say, if I had enough reputation,
I'd vote up your response. Yet we still disagree:
on a matter of semantics, and
on a central point of fact
First I claim, not without irony, we're having a semantic debate about the
meaning of 'ambiguity'.
When it comes to parsing and programming language semantics (the subject
of this question), surely you would admit a broad spectrum of the notion
'ambiguity'. Let's just adopt some random notation:
ambiguous: lexical ambiguity (lex must 'look ahead')
Ambiguous: grammatical ambiguity (yacc must defer to parse-tree analysis)
AMBIGUOUS: ambiguity knowing everything at the moment of execution
(and there's junk between 2-3 too). All these categories are resolved by
gathering more contextual info, looking more and more globally. So when you
say,
"qwerty = 4" is UNAMBIGUOUS in C#
when there is no variable defined...
I couldn't agree more. But by the same token, I'm saying
"qwerty = 4" is un-Ambiguous in ruby
(as it now exists)
"qwerty = 4" is Ambiguous in C#
And we're not yet contradicting each other. Finally, here's where we really
disagree: Either ruby could or could not be implemented without any further
language constructs such that,
For "qwerty = 4," ruby UNAMBIGUOUSLY
invokes an existing setter if there
is no local variable defined
You say no. I say yes; another ruby could exist which behaves exactly like
the current in every respect, except "qwerty = 4" defines a new
variable when no setter and no local exists, it invokes the setter if one
exists, and it assigns to the local if one exists. I fully accept that I
could be wrong. In fact, a reason why I might be wrong would be interesting.
Let me explain.
Imagine you are writing a new OO language with accessor methods looking
like instances vars (like ruby & C#). You'd probably start with
conceptual grammars something like:
var = expr // assignment
method = expr // setter method invocation
But the parser-compiler (not even the runtime) will puke, because even after
all the input is grokked there's no way to know which grammar is pertinent.
You're faced which a classic choice. I can't be sure of the details, but
basically ruby does this:
var = expr // assignment (new or existing)
// method = expr, disallow setter method invocation without .
that is why it's un-Ambiguous, while and C# does this:
symbol = expr // push 'symbol=' onto parse tree and decide later
// if local variable is def'd somewhere in scope: assignment
// else if a setter is def'd in scope: invocation
For C#, 'later' is still at compile time.
I'm sure ruby could do the same, but 'later' would have to be at runtime, because
as ben points out you don't know until the statement is executed which case
applies.
My question was never intended to mean "do I really need the 'self.'?" or "what
potential ambiguity is being avoided?" Rather I wanted to know why was this
particular choice made? Maybe it's not performance. Maybe it just got the job
done, or it was considered best to always allow a 1-liner local to override a
method (a pretty rare case requirement) ...
But I'm sort of suggesting that the most dynamical language might be the one which
postpones this decision the longest, and chooses semantics based on the most contextual
info: so if you have no local and you defined a setter, it would use the setter. Isn't
this why we like ruby, smalltalk, objc, because method invocation is decided at runtime,
offering maximum expressiveness?
Well, I think the reason this is the case is because qwerty = 4 is ambiguous—are you defining a new variable called qwerty or calling the setter? Ruby resolves this ambiguity by saying it will create a new variable, thus the self. is required.
Here is another case where you need self.:
class A
def test
4
end
def use_variable
test = 5
test
end
def use_method
test = 5
self.test
end
end
a = A.new
a.use_variable # returns 5
a.use_method # returns 4
As you can see, the access to test is ambiguous, so the self. is required.
Also, this is why the C# example is actually not a good comparison, because you define variables in a way that is unambiguous from using the setter. If you had defined a variable in C# that was the same name as the accessor, you would need to qualify calls to the accessor with this., just like the Ruby case.
The important thing to remember here is that Ruby methods can be (un)defined at any point, so to intelligently resolve the ambiguity, every assignment would need to run code to check whether there is a method with the assigned-to name at the time of assignment.
Because otherwise it would be impossible to set local variables at all inside of methods. variable = some_value is ambiguous. For example:
class ExampleClass
attr_reader :last_set
def method_missing(name, *args)
if name.to_s =~ /=$/
#last_set = args.first
else
super
end
end
def some_method
some_variable = 5 # Set a local variable? Or call method_missing?
puts some_variable
end
end
If self wasn't required for setters, some_method would raise NameError: undefined local variable or method 'some_variable'. As-is though, the method works as intended:
example = ExampleClass.new
example.blah = 'Some text'
example.last_set #=> "Some text"
example.some_method # prints "5"
example.last_set #=> "Some text"

Resources