Ruby. Null-aware operators

1. The safe navigation operator

There are some languages that support object-oriented programming that have support for the so-called the safe navigation operator (SNO). Also it's known as optional chaining operator, safe call operator or null-conditional operator. The SNO is a binary operator that returns null if its first argument is null;
otherwise it returns the second argument.

It's used to avoid sequential explicit null checks and assignments and replace them with method/property chaining. In programming languages where the navigation operator (e.g. ".") leads to an error if applied to a null object, the safe navigation operator stops the evaluation of a method/field chain and returns null as the value of the chain expression. It's currently supported in languages such as Apache Groovy, Ruby, Swift, C#, Kotlin, CoffeeScript and others. There is currently no common naming convention for this operator, but SNO is the most widely used term.

The main advantage of using this operator is that it solves a problem commonly known as pyramid of doom. Instead of writing multiple nested ifs, programmers can just use usual chaining, but put question mark symbols before dots (or other characters used for chaining).

Ruby supports the &. safe navigation operator (also known as the lonely operator) since version 2.3.0

Let's consider concrete example of using safe navigation operator on Ruby. My current version of Ruby is 2.5.1

Let's say that we have two classes: Owner and Account:

class Owner
  attr_accessor :first_name, :last_name, :age

  def initialize(first_name:, last_name:, age:)
    self.first_name = first_name
    self.last_name = last_name
    self.age = age
  end

  def summary
    "Owner: first name: #{first_name}, last name: #{last_name}, age: #{age}"
  end
end

module Roles
  GUEST = 1
  USER = 2
  ADMIN = 4
end

class Account
  include Roles

  attr_accessor :owner, :role

  def initialize(owner, role = GUEST)
    self.owner = owner
    self.role = role
  end
end

Create instances of these classes like that

owner = Owner.new(
  first_name: 'John',
  last_name: 'Smith',
  age: 30
)

account = Account.new(owner, Roles::USER)

Now we can get a full information about owner from account by the following way

puts account.owner.summary

But what if, while creating instances of our classes, something goes wrong? Then when you try to get the full information about owner from account you won't have guarantees that this operation will be successful. Moreover, we can get an error and our system may fall. Here is an example of such a situation

account = Account.new(nil)
puts account.owner.summary

As result we get next error:

undefined method `summary' for nil:NilClass (NoMethodError)

So, to avoid this, you can use safe navigation operator &.

puts account&.owner&.summary

And instead of an error, we get nil (it's a null in Ruby)

2. The null coalescing operator

The null coalescing operator (called the Logical Defined-Or operator in Perl) is a binary operator that is part of the syntax for a basic conditional expression in several programming languages. While its behavior differs between implementations, the null coalescing operator generally returns the result of its first operand if it exists and isn't null.

In contrast to the ternary conditional if operator used as x ? x : y, but like the binary Elvis operator used as x ?: y, the null coalescing operator is a binary operator and thus evaluates its operands at most once, which is significant if the evaluation of x has side-effects.

In the ruby for these purposes, we can use the operator ||

some_variable = nil || 'default_value'

No comments :

Post a Comment