Help me understand 'self' vs current object


#1

I’m pretty mystified by this, so I would appreciate any insights…
This does involve a Rails/ActiveRecord object, but that shouldn’t matter
here, right?

I’m archiving an object when it gets deleted, so I’m chaining methods in
a Rails controller:
triplet.archive(@user.id).as_delete.save

But I checked the database and the flag never got reset from false. I
added some print statements to as_delete() to get this:

class ArchiveTriplet < ActiveRecord::Base
def as_delete
puts “MARKING: #{is_deleted}”
is_deleted = true
puts “MARKED: #{is_deleted}/#{self.is_deleted}”
return self
end
end

With an additional debug after as_delete() the log shows:
MARKING: false
MARKED: true/false
ARCHIVING: #[ArchiveTriplet…, is_deleted: false, …]

What?!

The easy solution is to change is_deleted everywhere to self.is_deleted,
but am I misunderstanding what ‘self’ is supposed to be? Is there
another keyword which means what I’ve been lead to believe ‘self’ should
mean? (ie. ‘this’ in Java)

Thanks,

-Chris
using: ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]


#2

On 02.05.2009 17:24, C. Dagnon wrote:

MARKING: false
MARKED: true/false
ARCHIVING: #[ArchiveTriplet…, is_deleted: false, …]

What?!

The easy solution is to change is_deleted everywhere to self.is_deleted,
but am I misunderstanding what ‘self’ is supposed to be? Is there
another keyword which means what I’ve been lead to believe ‘self’ should
mean? (ie. ‘this’ in Java)

You just tripped into the local variable trap. The very moment you
placed “is_deleted = true” in that code you told Ruby to allocate a
local variable which is called “is_deleted” and whose value is “true”.
When you place the explicit receiver “self.” before “is_deleted” Ruby
chooses the method which accesses object state and not the local
variable.

http://ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html#S3

Kind regards

robert


#3

On Saturday 02 May 2009, C. Dagnon wrote:

|The easy solution is to change is_deleted everywhere to self.is_deleted

writing is_deleted = true creates a local variable and sets it to true.
Since
you don’t use that variable anywhere in your method, I guess that’s not
what
you want. I suppose what you want is to call the is_deleted= method
which is
an accessor for the @is_deleted instance variable. If it is so, then
changing
is_deleted= with self.is_deleted is not only an “easy solution” but
“the”
solution.

The reason is that writing

a_var = something

always means: create a local variable called a_var and assign it the
object
something. If you want to call a method ending in = on the current
object, you
need to explicitly tell it to ruby, using self.

|but am I misunderstanding what ‘self’ is supposed to be? Is there
|another keyword which means what I’ve been lead to believe ‘self’ should
|mean? (ie. ‘this’ in Java)

No, self is exactly what you think.

I hope this helps

Stefano


#4

Thanks for the informative responses,

I guess my polyglotism is bleeding too much. Wrong question caused by
wrong code. Though now I have to check if since it is an ActiveRecord
object what @is_deleted = true does to the mix.


#5

C. Dagnon wrote:

Help me understand ‘self’ vs current object

class A
def initialize
@x = 10
end

def x=(val)
@x = val
end

def x
@x
end

def test1
self.x = 0
end
end

a = A.new
puts a.x

a.test1
puts a.x

–output:–
10
0

So far so good.

class A
def meth
puts “hello”
end

def test2
meth
end
end

a.test2

–output:–
hello

Bingo. When ruby sees a method call without an object in front of it,
the implied caller is self. Inside the method test2, self is the object
that called test2. In this case, the object ‘a’ called test2, so inside
test2 self=a. The call to meth inside test2 has no object in front of
it, so the implied caller is self. As a result, calling meth is
equivalent to self.meth which is equivalent to a.meth.

Now consider this code:

class A
def test3
x = 0
end
end

a.x = 10
a.test3
puts a.x

What’s the output? Applying the previous lessons, ‘a’ is calling test3,
so inside test3 self is ‘a’. The method call ‘x=’ inside test3 does not
have an object in front of it, so the method call x= is equivalent to
self.x=, which is equivalent to a.x=. Here’s the output:

–output:–
10

What the??!! What happened? As the smart guys pointed out in another
current thread, when the ruby parser first encounters the line:

x = 10

it tags it with the message, “create a variable called x and assign 10
to it”. As a result, ruby dutifully follows the parser’s instructions
rather than slapping ‘self’ in front of x=. In other words, an
unadorned name with = after it causes a local variable to be created
rather than calling the ‘name=’ method.