Handling method calls to nullable objects

So I’m still on the learning curve and while I understand the error message OK, I’m unable to figure out how to make the call in a way that satisfies the compiler.

The cfg object has a property called common which is defined as nullable and common has a method called value. I thought checking if common was nil was the way to go, but obviously not.

There’s several strategies here depending a lot on context.

If your value is indeed nilable and you should be handling the nil case on the call side, do so:

if common = cfg.common
  puts common.value("key_1")
else
  puts "common is not set"
end

The compiler cannot guarantee that two subsequent calls to a method return the same value, so you have to assign the return value of the call to a local variable.

If progressing with nil when a part of the chain is nil is your way to go, try is your friend:

puts cfg.common.try &.value("key_1")

You could also alter the definition of common, to have common be not nilable, and a runtime error if it is after all, and common? be the nilable variant. This pattern is implemented by the getter!/property! macros

struct Config
  getter! common = maybe_set_a_value
end

puts cfg.common.value("key_1") unless cfg.common?

A shortcut to implementing the “raise on nil” behavior is calling .not_nil!, so the above is equivalent to

struct Config
   @common = maybe_set_a_value

  def common?
    @common
  end

  def common
    @common.not_nil!
  end
end
1 Like

Thanks for taking the time. Very informative. I’ve not seen the:

puts cfg.common.try &.value(“key_1”)

Before.

There is also a page about this in the docs: https://crystal-lang.org/reference/syntax_and_semantics/if_var.html

1 Like