Eli Sadoff Eli Sadoff - 1 month ago 9
Ruby Question

What does +@ mean as a method in ruby

I was reading some code and I saw something along the lines of

module M
def +@
self
end
end


I was surprised that this was legal syntax, yet when I ran
ruby -c
on the file it said it was fine.
-@
was also a legal method name yet when I tried
*@
or
d@
both of those were illegal. I was wondering what
+@
means and why is it legal?

Answer

Ruby contains a few unary operators, including +, -, !, ~, & and *. As with other operators you can also redefine these. For ~ and ! you can simply just say def ~ and def ! as they don't have a binary counterpart (e.g. you cannot say a!b).

However for - and + there is both a unary, and a binary version (e.g. a+b and +a are both valid), so if you want to redefine the unary version you have to use def +@ and def -@.

Also note that there is a unary version of * and & as well, but they have special meanings. For * it is tied to splatting the array, and for & it is tied to converting the object to a proc, so if you want to use them you have to redefine to_a and to_proc respectively.

Here is a more complete example showing all kinds of the unary operators:

class SmileyString < String
  def +@ 
    SmileyString.new(self + " :)")
  end

  def -@ 
    SmileyString.new(self + " :(")
  end

  def ~ 
    SmileyString.new(self + " :~")
  end

  def !
    SmileyString.new(self + " :!")
  end

  def to_proc
    Proc.new { |a| SmileyString.new(self + " " + a) }
  end

  def to_a
    [SmileyString.new(":("), self]
  end
end

a = SmileyString.new("Hello")
p +a                 # => "Hello :)"
p ~a                 # => "Hello :~"
p *a                 # => [":(", "Hello"]    
p !a                 # => "Hello :!"
p +~a                # => "Hello :~ :)"
p *+!-~a             # => [":(", "Hello :~ :( :! :)"]
p %w{:) :(}.map &a   # => ["Hello :)", "Hello :("]

In your example the Module just simply defines an unary + operator, with a default value of not doing anything with the object (which is a common behaviour for the unary plus, 5 and +5 usually mean the same thing). Mixing in with any class would mean the class immediately gets support for using the unary plus operator, which would do nothing much.

For example:

module M
  def +@
    self
  end
end

p +"Hello"     # => NoMethodError: undefined method `+@' for "Hello":String

class String
  include M
end

p +"Hello"     # => "Hello"
Comments