---
title: Quirks of Assignment
teaser:
tags: web,ruby
author: Jon Yurek
published_on: 2007-05-30
---

If you've been using Ruby for any length of time, then you should know that you
can override assignment on object attributes, right? It's what you get from
`attr_accessor` (by way of `attr_writer`), and it's what you get when you define
a `something=` method (which is what `attr_writer` really does).

    >> class Foo
         def bar= val
           @bar = val
         end
       end
    >> f = Foo.new
    >> f.bar = :none
    >> p f
    #<Foo:0x319afc @bar=:none>

The setter is a method, completely normal, and you can call it with `send` like
any other. Trouble is that when you assign stuff in Ruby (that is, a simple `a =
b` statement), your setter doesn't act like a normal method. First off, all
assignments return the right-hand-side of the assignment, instead of what the
return value of the setter would be.

    >> def test= val
         @test = val.to_f
       end
    >> self.test = "12.34"
    => "12.34"
    >> self.send(:test=, "12.34")
    => 12.34

Secondly, if you use a getter method bare (like, say, `foo`) without having
defined it first, Ruby will try to access the local variable `foo` first. Seeing
it isn't there, it'll try to access the method on `self`. And then if it isn't
there, it'll go to `method_missing`. If you try this with a setter, though,
you'll find it won't get past the local variable... Ruby will just set it and
continue on. You need to explicitly call it through `self` to get it to work.

    >> def foo= val
         puts val
         @foo = val
       end
    >> foo = 1
    => 1
    >> self.foo = 1
    1
    => 1

Both of these quirks have caught me before in rather unexpected ways, most
annoyingly the first one, because I fully expected the return value of the
statement to be the return value of the setter. Getters work fine without being
referenced through an object, just remember to add `self` before setters, or you
may find yourself wondering wtf is going on, since everything looks right.
