self.x=(value) in private?

P

Patrick Gundlach

Hello Rubyists,

I am slightly confused with calling a private method:

--------------------------------------------------
class Foo
def without_self
x=5
end
def with_self
self.x=5
end
def call_priv_with_self
self.priv
end

private

def x=(value)
puts "x=#{value}"
end

def priv
puts "priv"
end

end

Foo.new.without_self # no output
Foo.new.with_self # output "x=5"
Foo.new.call_priv_with_self # bang
--------------------------------------------------

I guess the first call is just an assignment to the variable x. But
from my understanding of pickaxe2, 329, Variable/Method Ambiguity this
should not be the case, because Ruby did not encounter an assignment
before.

The second call works, although it is a private method and I learned
that private methods must not have a receiver, as 'proved' in line
three.

So my two questions are: why is there no method call in
Foo#without_self? And why does self.x= report an error?

Patrick
 
D

Daniel Brockman

Hi Patrick,
class Foo
def without_self
x=3D5
end

def with_self
self.x=3D5
end
=20
private
=20
def x=3D(value)
puts "x=3D#{value}"
end

[...]

Why is there no method call in Foo#without_self?

An expression that looks like =E2=80=98identifier =3D value=E2=80=99 alwa=
ys
sets a variable, and never calls a method. This is simply
the way the language is defined.

When you want to call a setter method on the current object,
you *have* to say =E2=80=98self.foo =3D bar=E2=80=99, precisely because i=
f you
leave out the =E2=80=98self.=E2=80=99, you will just create a local varia=
ble.

(You may encounter code that has each setter method aliased
to a names like =E2=80=98set_foo=E2=80=99 or =E2=80=98set_bar=E2=80=99. =
This of course
removes the need for the =E2=80=98self.=E2=80=99 prefix, because =E2=80=98=
set_foo=E2=80=99
and =E2=80=98set_bar=E2=80=99 can be called directly.)
And why does self.x=3D [not] report an error?

As you have already pointed out yourself, private methods
may not normally be called with an explicit receiver.
However, there is an exception to this rule which says that
private setter methods *may* be called with an explicit
receiver, provided that explicit receiver is exactly =E2=80=98self=E2=80=99=
 
P

Patrick Gundlach

Daniel,

thank you for your explanations.


[...]
An expression that looks like ‘identifier = value’ always
sets a variable, and never calls a method. This is simply
the way the language is defined.

Then this part in Pickaxe II is the first section that irritates me.

Now that I know that this behaviour is intentional, I can use it in my
coode.

Regards,

Patrick
 
H

Hal Fulton

Patrick said:
Daniel,
=20
thank you for your explanations.
=20
=20
[...]
=20
=20
An expression that looks like =E2=80=98identifier =3D value=E2=80=99 al= ways
sets a variable, and never calls a method. This is simply
the way the language is defined.
=20
=20
Then this part in Pickaxe II is the first section that irritates me.
=20
Now that I know that this behaviour is intentional, I can use it in my
coode.

A writer method (ending in =3D) is a bit of a special case.
Ordinary methods work as you were expecting.


Hal
 
J

James Edward Gray II

Then this part in Pickaxe II is the first section that irritates me.

What's wrong with the Pickaxe II here? Can you point to the problem =20
section?

James Edward Gray II
 
P

Patrick Gundlach

What's wrong with the Pickaxe II here? Can you point to the problem =20
section?

Oh, I see, I misread the example. I was talking about 'Variable/Method
Ambiguity', Chapter 22, page 329 and I thought that is also related to
assignment. But that is not stated there. Thanks for asking again, so I
reread the section and made things clearer. (Although the description
of Attribute Assignment, p. 350 did not mention the special case that
these methods can be private).

Patrick
 
M

Mark Volkmann

An expression that looks like 'identifier =3D value' always
sets a variable, and never calls a method. This is simply
the way the language is defined.
=20
When you want to call a setter method on the current object,
you *have* to say 'self.foo =3D bar', precisely because if you
leave out the 'self.', you will just create a local variable.

I just want to make sure I fully understand this.

Isn't the preferred way of doing this the following?

@foo =3D bar

Is this equivalent to

self.foo =3D bar

Is this true?

An expression that looks like '@attr-name =3D value' always calls a
method whose name is 'attr-name=3D'.

--=20
R. Mark Volkmann
Partner, Object Computing, Inc.
 
S

Stefan Lang

I just want to make sure I fully understand this.

Isn't the preferred way of doing this the following?

@foo = bar

Is this equivalent to

self.foo = bar

Is this true?

Often it has the same effect.
An expression that looks like '@attr-name = value' always calls a
method whose name is 'attr-name='.

No it's the other way round. Most methods looking like 'attr_name='
are implemented like this:

# public accessor method
def attr_name=(val)
# Set instance variable @attr_name
# @attr_name is only accessible in methods of self
@attr_name = val
end

Let's look at an example:

% cat foo.rb
class Foo
def initialize
@text = ""
end
def text=(val)
# an empty string is a "true value" in Ruby,
# nil is a "false value"
@text = val || ""
end
def text
# just return @text
@text
end
def set_nil
@text = nil
end
end

a = Foo.new
a.text = nil
b = Foo.new
b.set_nil
p a.text
p b.text
% ruby foo.rb
""
nil
 
S

Stefan Lang

No it's the other way round. Most methods looking like 'attr_name='
are implemented like this:

# public accessor method
def attr_name=(val)
# Set instance variable @attr_name
# @attr_name is only accessible in methods of self
@attr_name = val
end

Let's look at an example:

% cat foo.rb
class Foo
def initialize
@text = ""
end
def text=(val)
# an empty string is a "true value" in Ruby,
# nil is a "false value"
@text = val || ""
end
def text
# just return @text
@text
end
def set_nil
@text = nil
# replace the above line with:
# self.text = nil
# and the method text= we've defined above will
# be called
end
end

a = Foo.new
a.text = nil
b = Foo.new
b.set_nil
p a.text
p b.text
% ruby foo.rb
""
nil

HTH,
Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,949
Members
47,500
Latest member
ArianneJsb

Latest Threads

Top