Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 (to lint) it said it was valid. -@ 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?

like image 942
Eli Sadoff Avatar asked Oct 16 '16 15:10

Eli Sadoff


People also ask

What does method mean in Ruby?

A method in Ruby is a set of expressions that returns a value. With methods, one can organize their code into subroutines that can be easily invoked from other areas of their program. Other languages sometimes refer to this as a function. A method may be defined as a part of a class or separately.

How do I use a method in Ruby?

We call (or invoke) the method by typing its name and passing in arguments. You'll notice that there's a (words) after say in the method definition. This is what's called a parameter. Parameters are used when you have data outside of a method definition's scope, but you need access to it within the method definition.

What def means in Ruby?

The code def hi starts the definition of the method. It tells Ruby that we're defining a method, that its name is hi . The next line is the body of the method, the same line we saw earlier: puts "Hello World" . Finally, the last line end tells Ruby we're done defining the method.

What does it mean when a method ends with in Ruby?

Ruby doesn't treat the ! as a special character at the end of a method name. By convention, methods ending in ! have some sort of side-effect or other issue that the method author is trying to draw attention to.


1 Answers

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 (using ruby <=2.2):

module M
  def +@
    self
  end
end

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

class String
  include M
end

p +"Hello"     # => "Hello"

Note that in this example you can clearly see from the error message that the +@ method is missing from the class

Note that the above example will be different from Ruby 2.3, as the unary minus and plus are defined for Strings since that version, and they refer to returning a frozen and unfrozen string from the original.

like image 87
SztupY Avatar answered Nov 15 '22 20:11

SztupY