Saturday, May 28, 2016

Ruby operators: equality, comparison, pattern matching and ordering

An operator is a character or a small set of characters that represent an action which is applied to one or more operands. Ruby provides many different kinds of operators; this post covers equality, comparison, pattern matching and ordering operators, all of which are implemented as methods. When one of those operators is reached within the code, it calls the corresponding method. When we type 2+3, we are actually calling the + method of the Integer class and providing 3 as an argument. We can rewrite it as 2.+(3) and get the same result.

Operator overloading means changing the behavior of an operator by overriding its corresponding method. That is, however, outside the scope of this post.

Equality operators: == and !=


The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.


"koan" == "koan" # Output: => true

The != operator, AKA inequality or bang-tilde, is the opposite of ==. It will return true if both objects are not equal and false if they are equal.


"koan" != "discursive thought" # Output: => true

Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.

When comparing numbers of different types (e.g., integer and float), if their numeric value is the same, == will return true.


2 == 2.0 # Output: => true

Additional methods for testing equality


equal?


Unlike the == operator which tests if both operands are equal, the equal method checks if the two operands refer to the same object. This is the strictest form of equality in Ruby.

Example:

a = "zen"
b = "zen"

a.object_id  # Output: => 20139460
b.object_id  # Output :=> 19972120

a.equal? b  # Output: => false

In the example above, we have two strings with the same value. However, they are two distinct objects, with different object IDs. Hence, the equal? method will return false.

Let's try again, only this time b will be a reference to a. Notice that the object ID is the same for both variables, as they point to the same object.


a = "zen"
b = a

a.object_id  # Output: => 18637360
b.object_id  # Output: => 18637360

a.equal? b  # Output: => true

eql?


In the Hash class, the eql? method it is used to test keys for equality. Some background is required to explain this. In the general context of computing, a hash function takes a string (or a file) of any size and generates a string or integer of fixed size called hashcode, commonly referred to as only hash. Some commonly used hashcode types are MD5, SHA-1, and CRC. They are used in encryption algorithms, database indexing, file integrity checking, etc. Some programming languages, such as Ruby, provide a collection type called hash table. Hash tables are dictionary-like collections which store data in pairs, consisting of unique keys and their corresponding values. Under the hood, those keys are stored as hashcodes. Hash tables are commonly referred to as just hashes. Notice how the word hash can refer to a hashcode or to a hash table. In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.

Ruby provides a built-in method called hash for generating hashcodes. In the example below, it takes a string and returns a hashcode. Notice how strings with the same value always have the same hashcode, even though they are distinct objects (with different object IDs).


"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547
"meditation".hash  # Output: => 1396080688894079547

The hash method is implemented in the Kernel module, included in the Object class, which is the default root of all Ruby objects. Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.


Symbol.instance_method(:hash).owner  # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel

String.instance_method(:hash).owner  # Output: => String
Hash.instance_method(:hash).owner  # Output: => Hash

In Ruby, when we store something in a hash (collection), the object provided as a key (e.g., string or symbol) is converted into and stored as a hashcode. Later, when retrieving an element from the hash (collection), we provide an object as a key, which is converted into a hashcode and compared to the existing keys. If there is a match, the value of the corresponding item is returned. The comparison is made using the eql? method under the hood.


"zen".eql? "zen"    # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true

In most cases, the eql? method behaves similarly to the == method. However, there are a few exceptions. For instance, eql? does not perform implicit type conversion when comparing an integer to a float.


2 == 2.0    # Output: => true
2.eql? 2.0 # Output: => false
2.hash == 2.0.hash # Output: => false

Case equality operator: ===


Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as case-equality, triple equals or threequals. Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on. Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left. For instance, it can be used to test if an object is an instance of a class (or one of its subclasses).


String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

The same result can be achieved with other methods which are probably best suited for the job, such as is_a? and instance_of?.

Range Implementation of ===


When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.


(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true ("a".."d") === "e" # Output: => false

Remember that the === operator invokes the === method of the left-hand object. So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.

Regexp Implementation of ===


Returns true if the string on the right matches the regular expression on the left.

/zen/ === "practice zazen today"  # Output: => true
# is similar to
"practice zazen today"=~ /zen/

The only relevant difference between the two examples above is that, when there is a match, === returns true and =~ returns an integer, which is a truthy value in Ruby. We will get back to this soon.

Implicit usage of the === operator on case/when statements


This operator is also used under the hood on case/when statements. That is its most common use.


minutes = 15

case minutes
  when 10..20
    puts "match"
  else
    puts "no match"
end

# Output: match

In the example above, if Ruby had implicitly used the double equal operator (==), the range 10..20 would not be considered equal to an integer such as 15. They match because the triple equal operator (===) is implicitly used in all case/when statements. The code in the example above is equivalent to:


if (10..20) === minutes
  puts "match"
else
  puts "no match"
end

Pattern matching operators: =~ and !~


The =~ (equal-tilde) and !~ (bang-tilde) operators are used to match strings and symbols against regex patterns.

The implementation of the =~ method in the String and Symbol classes expects a regular expression (an instance of the Regexp class) as an argument.


"practice zazen" =~ /zen/   # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil

:zazen =~ /zen/    # Output: => 2
:zazen =~ /discursive thought/  # Output: => nil

The implementation in the Regexp class expects a string or a symbol as an argument.


/zen/ =~ "practice zazen"  # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil

In all implementations, when the string or symbol matches the Regexp pattern, it returns an integer which is the position (index) of the match. If there is no match, it returns nil. Remember that, in Ruby, any integer value is "truthy" and nil is "falsy", so the =~ operator can be used in if statements and ternary operators.


puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes

Pattern-matching operators are also useful for writing shorter if statements. Example:


if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin" 
  true
end
Can be rewritten as:

if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
  true
end

The !~ operator is the opposite of =~, it returns true when there is no match and false if there is a match.

Comparison operators


Objects such as numbers and strings, which can be compared (amongst themselves) in terms of being greater or smaller than others, provide the <=> method, also known as the spaceship method. When comparing two objects, <=> returns -1 if the first object is lesser than the second (a < b), 0 in case they are equal (a == b) and 1 when the first object is greater than the second (a > b).


5 <=> 8  # Output:  => -1
5 <=> 5 # Output: => 0
8 <=> 5 # Output: => 1

Most comparable or sortable object classes, such as Integer, Float, Time and String, include a mixin called Comparable, which provides the following comparison operators: < (less than), <= (less than or equal), == (equal), > (greater than), >= (greater than or equal). These methods use the spaceship operator under the hood.

Let's find out which classes include the Comparable mixin:


ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Comparable }
Output:

=> [Complex, Rational, Time, File::Stat, Bignum, Float, Fixnum, Integer, Numeric, Symbol, String, Gem::Version, IRB::Notifier::NoMsgNotifier, IRB::Notifier::LeveledNotifier]

Comparison operators can be used in objects of all the above classes, as in the following examples.


# String
"a" < "b" # Output: => true
"a" > "b" # Output: => false

# Symbol
:a < :b  # Output: => true
:a > :b  # Output: => false

# Fixnum (subclass of Integer)
1 < 2  # Output: => true
2 >= 2  # Output: => true

# Float
1.0 < 2.0 # Output: => true
2.0 >= 2.0 # Output: => true

# Time
Time.local(2016, 5, 28) < Time.local(2016, 5, 29) # Output: => true

When comparing numbers of different classes, comparison operators will implicitly perform simple type conversions.


# Fixnum vs. Float
2 < 3.0  # Output: => true
2.0 > 3  # Output: => false

Monday, May 16, 2016

Procs and Lambdas: Closures in Ruby

In Ruby, almost everything is an object


In order to grasp closures, it's useful to understand some particularities of Ruby.

The Ruby documentation states that "In Ruby, everything is an object." Actually, it depends on our definition of "everything". Lucas Carlson provides a more accurate definition in his book Ruby Cookbook: "In Ruby, everything that can be assigned to a variable is an object".

There are two important exceptions to the "everything is an object" rule: blocks and methods are not objects..

Introduction to Closures


A closure is an object with the following characteristics:
  • It can access variables defined in the scope on which it was defined and remembers the values of all variables available in that scope, even when called on another scope or when those variables are no longer available (out of scope).
  • It is an object. Hence, it can be assigned to a variable, passed around, called from within different scopes, etc.

In contrast, a regular method can only be called from within the scope on which it was defined and can only access variables received as arguments.

Below is an example using a Lambda. The same could be done using a Proc.


def meditate
    minutes = 40
    return lambda { minutes }
end
 
p = meditate
minutes = nil
p.call # Output: => 40

Notice that, when we called the lambda, the meditate method was already gone. We also set the value of minutes to nil. Nonetheless, the lambda remembered the initial value of minutes.

Ruby has two types of closures: Lambdas and Procs.

Methods are not closures, this is explained in this post. Also, many authors state that blocks are closures, but they are not, as explained in this post.

Procs


Procs are very similar to blocks, with a few important differences:
  • Unlike blocks, procs are objects and can be assigned to variables.
  • Procs are closures, blocks are not (as seen above).
  • Unlike blocks, we can pass multiple Procs to a method as arguments.

Basic Syntax


Procs are defined by calling Proc.new and called with the call method. The most basic syntax for defining a proc is:


p = Proc.new { puts "Hello!" }
p.call # Output: Hello!

The syntax for multi-line procs is:

p = Proc.new do
    print "Hello! "
    print "Goodbye!"
end
p.call # Output: Hello! Goodbye!

Passing multiple procs to a single method


We can pass multiple procs to a single method as arguments.


def multi_proc_demo(p1, p2)
    p1.call
    p2.call
end

p1 = Proc.new { puts "Hello from the first proc" }
p2  = Proc.new { puts "Hello from the second proc " }

multi_proc_demo(p1, p2)
Output:

Hello from the first proc
Hello from the second proc

Procs can take arguments


Procs can also have parameters and take arguments.


p = Proc.new { |name| puts "Hello, #{name}!" }
p.call "Eihei Dogen" # Output: Hello, Eihei Dogen!

Multi-line syntax with arguments:


p = Proc.new do |name|
    puts "Hello, #{name}!"
end

p.call "Eihei Dogen" # Output: Hello, Eihei Dogen!

In the example below, when calling the meditate method, we will provide a proc that takes an argument called "name".


def meditate(p)
    p.call 'zazen'  # zazen is an argument passed by the method to the proc
end

meditate Proc.new {|name| puts "Today we will practice #{name}."}
Output:

Today we will practice zazen.

Unlike a method, when a proc expects an argument and we don't provide one, it runs normally and defaults the missing argument value to nil.


p = Proc.new { |name| puts "Hello, #{name}!" }
p.call # Output: Hello, !

A proc handles arguments with greater flexibility than a method or a lambda. In addition to defaulting missing argument values to nil, a proc also silently discards unexpected arguments, implicitly unpacks arrays of arguments, etc. This behavior can be useful in some cases, but it usually makes it harder to notice and debug argument mismatches.

Starting at Ruby 1.9, we can also use the following alternative syntax to call a proc:


p["Eihei Dogen"]
p.("Eihei Dogen")
p::("Eihei Dogen")
p === "Eihei Dogen"
p.yield "Eihei Dogen"

Even though Ruby provides multiple ways to call a proc, it's usually a good idea to stick with the plain old call method in order to write code that is easier to read for future maintainers.

Procs and return statements


Another important difference between a proc and a method or lambda is the way in which they handle the return statement. If a method is defined inside another method, the return statement in the inner method exits only from the inner method itself, then the outer method continues executing. The same goes for defining a lambda within a lambda, a lambda inside a method or a method within a lambda. However, when a proc is defined within a method, the return statement will exit from the proc as well as the outer (enclosing) method. Example:


def meditate
    puts "Adjusting posture…"
    p = Proc.new { puts "Ringing bell…"; return }
    p.call
    puts "Sitting still…"  # This is not executed
end 

meditate
Output:

Adjusting posture…
Ringing bell…

Notice how the last line of the method was not executed because the return statement within the proc has exited from both the proc and the enclosing method.

If we define a proc without an enclosing (outer) method and use a return statement, it will throw a LocalJumpError.


p = Proc.new { puts "Ringing bell…"; return }
p.call
Output:

Ringing bell…
LocalJumpError: unexpected return

This happens because when a return statement is reached within a proc, instead of returning from the context where it was called, it returns from the scope on which it (the proc) was defined. In the following example, a LocalJumpError happens because the proc is trying to return from the top-level environment, where it was defined.


def meditate p
    puts "Adjusting posture…"
    p.call
    puts "Sitting still…"  # This is not executed
end

p = Proc.new { puts "Ringing bell…"; return }

meditate p 
Output:

Adjusting posture…
Ringing bell…
LocalJumpError: unexpected return

Usually, it's not a good idea to use a return statement within a proc. Procs are usually passed around between methods and if the method on which the proc was defined has already returned, it will throw an exception. In the example below we could just remove the return statement. However, there are cases we actually need to return something. In the latter, it's probably best to use a lambda instead of a proc. We will see later that lambdas handle return statements in a different way, more like methods.

Below is another scenario involving return statement:


def zafu_factory
    # This method will return the following proc implicitly
    Proc.new { puts "Round black zafu"; return }
end

def meditate
    puts "Adjusting posture…"
    p = zafu_factory
    p.call
    puts "Sitting still…"  # This is not executed
end 

meditate
Output:

Adjusting posture…
Round black zafu
LocalJumpError: unexpected return

What just happened? The zafu_factory method created and implicitly returned a proc. Then, the proc was called by the meditate method and when the return statement within the proc was reached, it tried to return from the context on which it was defined (the zafu_factory method). However, zafu_factory already returned the proc and a method can only return once each time it's called. In other words, an exception was thrown because the zafu_factory method had already returned when the proc was called and tried to return a second time.

The next statement


If all we need is to exit prematurely from a proc, we can use a next statement.


p = Proc.new { puts "Ringing bell…"; next; puts "Throwing up zafus" }
p.call # Output: Ringing bell…

Notice that, in the example above, no LocalJumpError was raised. Also, the code after the next statement was never executed and, luckily, no zafus (meditation cushions) were thrown. Now let's try it inside a method:


def meditate
    puts "Adjusting posture…"
    p = Proc.new do
        puts "Ringing bell…"
        next
        puts "Throwing up zafus"
    end
    p.call
    puts "Sitting still…"  # This line *is* executed
end

meditate
Output:

Adjusting posture…
Ringing bell…
Sitting still…

Notice that:
  • The proc exits immediately when the next statement is reached (no zafus were thrown up).
  • When the proc exits, the execution of the enclosing (outer) method is resumed and the line below the proc (puts "Sitting still…") runs normally.

Differences between Proc and Block

  • Unlike blocks, procs are objects, hence they can be assigned to variables and passed around.
  • We can pass multiple Procs to a method, but only a single block.

Available methods in the Proc class


To see all available methods that can be called on a proc, which is always an instance of the Proc class, we can do this:


Proc.instance_methods.sort
=> [:!, :!=, :!~, :<=>, :==, :===, :=~, :[], :__id__, :__send__, :arity, :binding, :call, :class,
 :clone, :curry, :define_singleton_method, :display, :dup, :enum_for, :eql?, :equal?, :extend,
 :freeze, :frozen?, :hash, :inspect, :instance_eval, :instance_exec, :instance_of?, 
 :instance_variable_defined?,  :instance_variable_get, :instance_variable_set, :instance_variables,
 :is_a?, :itself, :kind_of?, :lambda?, :method, :methods, :nil?, :object_id, :parameters, 
 :private_methods, :protected_methods, :public_method, :public_methods,:public_send,
 :remove_instance_variable, :respond_to?, :send, :singleton_class, :singleton_method, 
 :singleton_methods, :source_location, :taint, :tainted?, :tap, :to_enum, :to_proc, :to_s, 
 :trust, :untaint, :untrust, :untrusted?, :yield]

The following is a list of instance methods defined in the Proc class (not inherited from other classes or modules). Notice that when the instance_methods method receives the false flag, it ommits inherited instance methods.


Proc.instance_methods(false).sort 
=> [:[], :arity, :binding, :call, :curry, :lambda?, :parameters, :source_location, :to_proc, :yield]

Covering all those methods is outside the scope of this post. Information about them is available at the Ruby Documentation.

Lambdas


Lambdas are anonymous functions, which means they are functions with no name. They are objects and therefore can be stored inside variables and passed around.

Lambdas compared to procs


Lambdas are instances of the Proc class.


Proc.new { } # Output: => #<Proc:0x00000001295210@(irb):153>
lambda {}  # Output: => #<Proc:0x00000001312b48@(irb):154 (lambda)>

While lambdas and procs are similar in many ways, there are some important differences:
  • Return statement behavior: Like a method, a lambda can return a value using the return statement. A proc cannot do that. Also, when a return statement is reached within a lambda, it will return execution to the outer method on which it was defined. When a Proc encounters a return statement, it will exit from both the proc itself and the enclosing method (method on which the proc was defined).
  • Handling missing arguments: When a lambda expects arguments and we don't provide them, or we provide the wrong number of arguments, an exception is thrown. When a Proc expects an argument and doesn't receive it, it runs and defaults the missing argument value to nil.

Lambdas compared to methods


In his book The Ruby Programming Language, Yukihiro Matsumoto (the creator of Ruby, AKA Matz) explains "A proc is the object form of a block, and it behaves like a block. A lambda has slightly modified behavior and behaves more like a method than a block. Calling a proc is like yielding to a block, whereas calling a lambda is like invoking a method. "

As discusses above, lambdas are similar to methods in how they handle arguments and return statements.
The most important difference between lambdas and methods is that the former is a closure and the latter is not. In other words, lambdas can:
  • Be assigned to variables and passed around (as they are objects);
  • Access and remember the values of all variables in the outer scope (in which they were defined).

Basic Syntax


The most basic syntax for defining a lambda is:


l = lambda { puts "Hello" }
l.call # Output: Hello

Notice we are calling the built-in lambda method and passing it a block.

As of Ruby 1.9, a new syntax called "stabby lambda" is supported:


l = ->{ puts "Hello!" }
l.call # Output: Hello!

There is also the do ... end syntax, suited for multi-line lambdas:


l = lambda do |message|
    puts message
end

l.call "Hey there" # Output: Hey there

How lambdas handle arguments


Just like in methods, we can set parameters when defining a lambda and pass arguments when calling it.


l = lambda { |name| puts "Today we will practice #{name} meditation." }
l.call "zazen" # Output: Today we will practice Zazen meditation.

Same example in the "stabby" syntax:


l = -> (name) { puts "Today we will practice #{name} meditation." }
l.call "zazen" # Output: Today we will practice Zazen meditation.

Notice the absence of space between the stabby operator (->) and the name argument. As of Ruby 2.0 introducing a space has no effect, however, on Ruby 1.9 it is invalid syntax and will fail.

When a lambda expects arguments and we don't provide them, or we provide the wrong number of arguments, an exception is thrown.


l = lambda { |name| puts "Today we will practice #{name} meditation." }
l.call
ArgumentError: wrong number of arguments (given 0, expected 1)

We can use the arity method to find out the number of expected arguments:


l.arity  # Output: => 1

Just like methods, lambdas accept all of the following types of parameters/arguments:
  • Positional parameters (required and optional)
  • Single splat parameter (*);
  • Keyword parameters (required and optional);
  • Double splat parameter (**);
  • Explicit block parameter prefixed with ampersand (&).

The following examples illustrate the syntax of a lambda that takes multiple types of arguments.


# Stabby syntax
l = -> (cushion, meditation="kinhin", *room_items, time:, posture: "kekkafuza", **periods, &p) do
  p.call
end

# Regular syntax
l = lambda do |cushion, meditation="kinhin", *room_items, time:, posture: "kekkafuza", **periods, &p|
  p.call
end

l.call("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon" ) { puts "Hello from inside the block, which is now a proc." }
Output:

Hello from inside the block, which is now a proc.

Lambdas handle arguments the same way as methods. There is a comprehensive explanation of all the above parameter/argument types in this post about methods

There is an exception though. In Ruby, we can pass a block as an implicit argument to any method and execute it with a yield statement. This is covered in this post about blocks. Lambdas are different as they will not accept a block as an implicit argument. However, as seen above, we can pass a block to a lambda as an explicit argument (prefixed with ampersand) and execute it with the call method. We can also pass procs and other lambdas to a lambda as arguments. Example:


lambda1 = -> { puts "Hello from lambda1" } 
lambda2 = ->(other_lambda) do
  other_lambda.call
  puts "Hello from lambda2"
end

lambda2.call lambda1
Output:

Hello from lambda1
Hello from lambda2

Different ways to call a lambda


Starting at Ruby 1.9, we can also use any of the syntax below to call a lambda and provide arguments:


l["Eihei Dogen"]
l.("Eihei Dogen")
l::("Eihei Dogen")
l === "Eihei Dogen"
l.yield "Eihei Dogen"

Even though Ruby provides multiple ways to call a lambda, using the call method will probably make the code easier to read.

Lambdas and return statements


Lambdas also handle return statements in the same way as methods. When reached, a return statement will exit from the lambda itself and return execution to the outer (enclosing) method. Return statements are optional and, just like methods, lambdas will implicitly return the last evaluated expression. This post about methods contains a longer explanation.

Saturday, May 7, 2016

Ruby Methods

A method is a way of grouping related code into a single container. In other words, methods are named chunks of code that can be reused. Usually, methods take some data (called input or arguments), does something with that input and gives back a result (called return or output).

Basic Syntax


We'll start by creating a simple method that does not take any arguments (input) nor returns anything. A methods definition begins with the def keyword and ends with an end keyword.


def say_hello
    puts "Hello!"
end

We can execute our method just by calling it's name:


say_hello
Output:

Hello!

Positional Arguments


Usually the terms parameter and argument are used interchangeably. In a stricter sense, a parameter (AKA formal parameter) is defined at the method declaration and an argument (AKA actual parameter) is the data provided to the method at calling time, which is "passed through" a parameter.

In the example below, we'll create a method that takes an argument called name. All we have to do is include the parameter name after the method name and it's value (passed at calling time) will be available inside the method:


def say_hello name
    puts "Hello, #{name}!"
end

say_hello "dear visitor"  # Call the method and provide the the string "dear visitor" as an argument
Output:

Hello, dear visitor!

We can also enclose the arguments in parentheses when calling a method, the output will be the same. Example:


say_hello("dear visitor")

Methods can also have multiple parameters and hence take multiple arguments, like this:


def greet time, name, *foo
    puts "Good #{time}, #{name}!"
end

greet "morning", "dear visitor"
Output:

Good morning, dear visitor!

Notice that when we called the method, the arguments were provided in the same order as the corresponding parameters were specified when the method was defined. These are called positional arguments.

Keyword Arguments


When passing a large number of arguments to a method, the positional syntax used above can cause confusion. For instance, if we forget to include an argument when calling the method, all following arguments will be passed through the wrong parameters. In these cases, it's usually better to use keyword arguments, which allows us to switch the order of the arguments without affecting the result. Keyword arguments are passed by name, instead of by position.

As of Ruby 2.1, the basic syntax is:


def greet time:, name: 
    puts "Good #{time}, #{name}!"
end

In the example above, notice the colons following the parameter names. That is what makes them keyword parameters (AKA keyword arguments) instead of positional parameters.

Now let's call the method providing arguments by name:


greet time: "morning", name: "dear visitor"
Output:

Good morning, dear visitor!

Optional keyword arguments were introduced in Ruby 2.0 and mandatory keyword arguments (as seen in the example above) are available as of Ruby 2.1.

Optional arguments and default values


When a method expects arguments and we don't provide them, or we provide the wrong number of arguments, an exception is thrown.


def greet time, name 
    puts "Good #{time}, #{name}!"
end

greet
Output:

ArgumentError: wrong number of arguments (given 0, expected 2)

We can use the built-in arity method to find out the number of arguments expected by a method:


method(:greet).arity
=> 2

When called on a method that takes mandatory arguments only, arity returns the number of expected arguments. When invoked on a method that takes both mandatory and optional arguments, arity returns -n-1 where n is the number of required arguments. So, a method with 3 required arguments and any number of optional arguments has an arity of -4.

Methods can also have optional arguments. When a default value is set, the argument becomes optional. Example:


def greet time="afternoon", name="dear visitor"
    puts "Good #{time}, #{name}!"
end


greet  # Call the method without providing any arguments

Output:

Good afternoon, dear visitor!


The method was executed without any errors because both arguments are optional, as we have assigned them default values. The same can be done with keyword arguments:


def greet time: "afternoon", name: "dear visitor"
    puts "Good #{time}, #{name}!"
end

greet  # Call the method without providing any arguments
Output:

Good afternoon, dear visitor!

Splat (*) operator


Methods can take any number of arguments by prefixing a parameter with a * (splat) or a ** (double splat) operator. This is useful when the exact number of arguments is unknown at method definition.

First let's look at the * (splat) operator. All arguments passed through the parameter prefixed with * are automatically stored in an array.


def list_masters *names
    print names
end

# Call the method and pass it three arguments
list_masters "Shunryu Suzuki", "Thich Nhat Hanh", "Kodo Sawaki"
Output:

["Shunryu Suzuki", "Thich Nhat Hanh", "Kodo Sawaki"]

Notice the output is an array.

There are other uses for the splat operator in Ruby, such as unwraping an array when passing it to a method, coercing values into arrays and deconstructing arrays, but these are outside the scope of this post.

Double splat (**) operator


Now let's look at the ** (double splat) operator. It was was introduced in Ruby 2.0 and works in a similar way to the single splat operator, except it stores the arguments in a hash instead of an array. Let's try it:


def meditate **details
    print details
end

# Call the method and pass it three arguments
meditate mat: "zabuton", cushion: "zafu", practice: "shikantaza", time: 40
Output:

{:mat=>"zabuton", :cushion=>"zafu", :practice=>"shikantaza", :time=>40}

Notice that the output is a hash.

Parameters prefixed with double splat only accept keyword arguments, such as minutes: 40 or meditation: "zazen".

Mixing * and ** operators


If a method includes both single splat and double splat parameters, non-keyword arguments will be taken by the parameter prefixed with * and hash arguments will be taken by the parameter prefixed with **. Example:


def meditate *practices, **details
    puts "Practices: #{practices}"
    puts "Details: #{details}"
end

meditate"zazen", "kinhin", duration: 40, time: "morning"
Output:

Practices: ["zazen", "kinhin"]
Details: {:duration=>40, :time=>"morning"}

Notice that the arguments passed through the *practices parameter were inserted into an array and arguments passed through the **details parameter were stored into a hash.

When a method includes both * and ** parameters, all of the positional arguments should be provided first, then the keyword arguments. If we try to call the above method and provide the keyword arguments first, a syntax error is thrown:


meditate time: "morning", duration: 40, "zazen", "kinhin"
Output:

SyntaxError: (irb):59: syntax error, unexpected ',', expecting =>
meditate time: "morning", duration: 40, "zazen", "kinhin"
                                                ^

The ampersand (&) operator at method definition


When the last parameter of a method is prefixed with the ampersand (&) operator, it means the method is expecting a block. As seen in the Introduction to Blocks, any method can take a block as an implicit argument. However, this is different. When we define a method with the last parameter prefixed with &, any block passed to the method will be converted into a proc (the to_p method is invoked under the hood) and assigned to the parameter.


def tester &foo
    puts "foo is a #{foo.class}"
    foo.call  # call the proc
end

tester { puts "Hello from the proc" }
Output:

foo is a Proc
Hello from the proc

Notice in the example above that the block (which is now a proc) was assigned to the foo variable. We would not be able to do that to a block as blocks are not objects and cannot be assigned to variables.

Even though the block is converted into a proc, it is also treated as the method's block, hence we can execute it with either call (as seen above) or yield. Example:


def tester &foo
    yield if block_given?
end

tester { puts "Hello from the block" }
Output:

Hello from the block

The ampersand (&) operator at method call


When calling a method, we can pass a proc as an argument and prefix it with the ampersand (&) operator. This will convert the proc into a block and pass it to the method.


def tester
  yield if block_given?
end

p = Proc.new { puts "Hello from the proc, converted to a block" }
tester &p
Output:

Hello from the proc, converted to a block

Lambdas are instances of the Proc class. Athough they handle arguments and return statements deifferently, they can also be passed to a method as an argument prefixed with & and converted into blocks.


l = lambda { puts "Hello from the lambda, converted to a block" }
tester &l
Output:

Hello from the lambda, converted to a block

Ampersand and object (&:method)


The & operator can also be used to pass an object as a block to a method, as in the following example:


arr = [ 1, 2, 3, 4, 5 ]

arr.map { |n| n.to_s } 
arr.map &:to_s

Both the examples above have the same result. In both, the map method takes the arr array and a block, then it runs the block on each element of the array. The code inside the block runs to_s on each element, converting it from integers to strings. Then, the map method returns a new array containing the converted items.

The first example is common and widely used. The second example may look a bit cryptic at first glance. Let's see what's happening:

In Ruby, items prefixed with colon (:) are symbols. If you are not familiar with the Symbol class/data type, I suggest you Google it and read a couple of articles before continuing. All method names in Ruby are internally stored as symbols. By prefixing a method name with a colon, we are not converting the method into a symbol, neither are we calling the method, we are just passing the name of the method around (referencing the method). In the example above, we are passing :to_s, which is a reference to the to_s method, to the ampersand (&) operator, which will create a proc (by calling to_proc under the hood). The proc takes a value as an argument, calls to_s on it and returns the value converted into a string.

Although the :to_s symbol is always the same, when running the map loop, it will refer to the to_s method of the class corresponding to each array item. If we passed an array such as [ 21, 4.453, :foobar, ] to the map method, the to_s method of the Fixnum class would be applied (called) on the first item, the to_s method of the Float class would be applied to the second item and the to_s method of the Symbol class would be applied to the third item. This makes sense because, as we learned above, we are not passing the actual to_s method to the ampersand operator, just its name.

Below is an example of creating a proc that takes an argument, calls a method on it and returns the result of the method.


p = :upcase.to_proc
p.call("foo bar")
Output:

 => "FOO BAR"

Let's review what is going on in arr.map &:to_s
  1. At each iteration of map, one item of the array (an integer) is passed to &:to_s
  2. The :to_s symbol (which is a reference to the to_s method) is passed to the & operator, which creates a proc that will take an argument (an array item), call to_s on the argument and return the value converted into string;
  3. The map method returns a new array containing the strings "1", "2", "3", "4" and "5".

Mixing all kinds of arguments


The method below includes all kinds of arguments discussed above. Notice that when mixing different kinds of parameters, they have to be included in the method definition in a specific order:
  1. Positional parameters (required and optional) and a single splat parameter, in any order;
  2. Keyword parameters (required and optional), in any order;
  3. Double splat parameter;
  4. Block parameter (prefixed with &);
The order above is somewhat flexible. We could define a method and begin the parameter list with a single splat argument, then a couple of optional positional arguments, and so on. Even though Ruby allows that, it's usually a very bad practice as the code would be hard to read and even harder to debug. It's usually best to use the following order:
  1. Required positional parameters;
  2. Optional positional parameters (with default values);
  3. Single splat parameter;
  4. Keyword parameters (required and optional, their order is irrelevant);
  5. Double splat parameter;
  6. Explicit block parameter (prefixed with &).
Let's see an example:


def meditate cushion, meditation="kinhin", *room_items, time: , posture: "kekkafuza", **periods, &b
    puts "We are practicing #{meditation}, for #{time} minutes, in the #{posture} posture (ouch, my knees!)."
    puts "Room items: #{room_items}"
    puts "Periods: #{periods}"
    b.call # Run the proc received through the &b parameter
end

meditate("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon" ) { puts "Hello from inside the block" }
Output:

We are practicing zazen, for 40 minutes, in the kekkafuza posture (ouch, my knees!).
Room items: ["zabuton", "incense"]
Periods: {:period1=>"morning", :period2=>"afternoon"}
Hello from inside the block

Notice that when calling the method, we have:
  1. Provided the cushion mandatory positional argument;
  2. Overwritten the default value of the meditation optional positional argument;
  3. Passed a couple of extra positional arguments (zabuton and incense) through the *room_items parameter;
  4. Provided the time mandatory keyword argument;
  5. Omitted the posture optional keyword argument;
  6. Passed a couple of extra keyword arguments (period1: "morning", period2: "afternoon") through the **periods parameter;
  7. Passed the block { puts "Hello from inside the block" } through the &b parameter;
Please note the example above servers only to illustrate the possibility of mixing different types of parameters. Building a method like this in real code would be a bad practice. If a method needs that many arguments, it's probably best to split it into smaller methods. If it's absolutely necessary to pass that much data to a single method, we should probably create a class to store the data in a more organized way, then pass an instance of that class to the method as a single argument. BTW, I will soon publish a post on classes, so stay tuned.

Returning a result


What if, instead of displaying the method result, we want to store it in a variable and pass it around? When a method terminates normally (it is not interrupted by an exception), it returns a value.

In the following example, we have included a return statement within the method.


def say_hello name
    return "Hello, #{name}!"
end

greeting = say_hello "dear visitor"
puts greeting
Output:

Hello, dear visitor!

Unlike many other programming languages, Ruby methods do not require a return statement in order to return something. If the return statement is omitted, the method returns the value of the last evaluated expression (last statement).

Both the examples below will have the same result as the one above:


def say_hello name
    "Hello, #{name}!"
end

Anoter example:


def clap hands
    if hands == 2
        "You can hear the sound of two hands when they clap together."
    else
        "Now show me the sound of one hand."
    end
end

koan = clap 2
puts koan
koan = clap 1
puts koan
Output:

You can hear the sound of two hands when they clap together.
Now show me the sound of one hand.

Methods can take and execute blocks


Please see the post Introduction to Blocks in Ruby to learn about using blocks with methods.

Optional parentheses on method calls

Unlike other languages, in Ruby parentheses are not required when calling a method, except when the passed arguments are ambiguous without parentheses. Suppose we have the following methods:


def method1 arg1, arg2
    return "#{arg1} #{arg2}"
end

def method2 a1
    return a1
end

Notice that the m1 method takes two arguments and m2 takes one argument. Now, we will try to call them like this:


method1 "foo", method2 "bar"
Output:

SyntaxError: (irb):175: syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '('
method1 "foo", method2 "bar"
                        ^

The error above happened because our method call was ambiguous. We intended to pass method2 (together with the argument "bar") as an argument to method1. However, method1 had no way of knowing if: "foo", method2 and "bar" are 3 distinct arguments passed to method 1 OR "foo" is a distinct argument passed to method 1 but "bar" is an argument for "method2", in which case m2 and "bar" should be treated by method1 as a single argument.

By using parentheses, we eliminate the ambiguity and the error:


method1("foo", method2("bar"))
Output:

 => "foo bar" 

In Ruby, all functions are actually methods


Generally speaking, a method is a function defined inside a class. In Ruby, all functions are methods.

When our code is not defined inside any specific context/scope, such as a class or a module, we are in the "top-level context". In Ruby, this context is called main and it is an instance of a built-in class called Object. This can be easily verified:


puts self.class
 => Object

All functions defined in the top-level context are private instance methods of the built-in Object class. So all functions inevitably belong to a class, hence they are actually methods. Let's verify:


def some_method
end

Object.method_defined?(:some_method)
Output:

 => true  # This proves that some_method was implicitly associated with the built-in Object class. 

Methods are not objects


In his book The Ruby Programming Language, Yukihiro Matsumoto (the creator of Ruby, AKA Matz) explains that "Methods are a fundamental part of Ruby’s syntax, but they are not values that Ruby programs can operate on. That is, Ruby’s methods are not objects in the way that strings, numbers, and arrays are. It is possible, however, to obtain a Method object that represents a given method, and we can invoke methods indirectly through Method objects."

So, methods are not objects in Ruby. This means a method cannot be stored in a variable, nor take another method as an argument or return another method. However, a method can be represented as an instance of the built-in Method Class, created by a built-in method called method. That is actually easier done than said:


def say_hello
    puts "Hello"
end

m = method(:say_hello)  # Create object representation of the say_hello method
m.call  # Call the say_hello method object
Output:

Hello

Notice in the example above we have passed the name of the say_hello method to the method method as a symbol, hence the colon in :say_hello. As we already learned, Ruby stores the names of all methods as symbols.

If we call the method method multiple times, a new method object with a distinct object ID is created each time. Therefore, the method objects are not references to the original method (which is not an object and does not have an object ID of its own), they are distinct objects, created on the fly.


method(:say_hello).object_id # Output: => 7604420
method(:say_hello).object_id # Output: => 6886380
method(:say_hello).object_id # Output: => 6840900

After creating the method object above, we can change the original method but the Method object remains unaltered:


def say_hello
    puts "Goodbye"
end

m.call
Output:

Hello

The examples above serve only to illustrate that methods are not objects, but Ruby provides an object representation for them. Calling a method through its object representation is less efficient than calling it directly. Most of the times, when we need to assign a method to a variable and pass it around, a Lambda will do the job in a simpler and more efficient way.

Methods are not closures


A closure has the following characteristics:
  • It remembers the values of all variables that were available in the scope it was defined, even when called on another scope or when those variables are no longer available.
  • It is an object. Hence it can be assigned to a variable, passed around, called from within different scopes, etc.
In Ruby, methods are not closures, neither are the Method objects. As stated by Yukihiro Matsumoto (Matz) in the book as mentioned earlier "One important difference between Method objects and Proc objects is that Method objects are not closures. Ruby's method are intended to be completely self-contained, and they never have access to local variables outside of their scope. The only binding retained by a Method object, therefore, is the value of self - the object on which the method is to be invoked."

In short, methods do not meet either of the two criteria above required to be a closure.

Naming conventions


Conventionally, method names begin with a lowercase letter and, when containing more than one word, use an underscore to separate words, as in "my_method" (AKA snake case).

Methods with names ending in question mark (?) usually return boolean values (true or false) and those ending in exclamation point (!) are generally mutator methods, which means they alter the received object instead of returning a new object. There are exceptions, though. In the context of a method name, question mark and exclamation point are just regular characters.

Thank you for reading.