Forum: Ruby Help me understand 'self' vs current object

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
40dc5a2806f0f2eb5ac7c663f2bb5af8?d=identicon&s=25 C. Dagnon (chrisd)
on 2009-05-02 17:24
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]
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-05-02 17:36
(Received via mailing list)
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_...

Kind regards

  robert
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2009-05-02 19:14
(Received via mailing list)
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
54404bcac0f45bf1c8e8b827cd9bb709?d=identicon&s=25 7stud -- (7stud)
on 2009-05-02 22:24
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.
40dc5a2806f0f2eb5ac7c663f2bb5af8?d=identicon&s=25 C. Dagnon (chrisd)
on 2009-05-12 16:27
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.
This topic is locked and can not be replied to.