# Nil check syntax confusion

**URL:** <https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668>\
**Category:** Help & Support\
**Created:** [August 27, 2021, 9:23am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668 "2021-08-27T09:23:33Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![yb66](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/yb66/32/739_2.png) [@yb66](https://forum.crystal-lang.org/u/yb66)\
**Post date:** [August 27, 2021, 9:23am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/1 "2021-08-27T09:23:33Z")

</div>

I’m wondering why the second version of `handling_nil` compiles fine but the first doesn’t.

```auto
class A
  @a : Array(Int32)?

  def from_the_database : Array(Int32)
    rand(1) == 1 ? [2] : [] of Int32
  end

  # This will not compile
  # $ crystal build tryit.cr
  # Showing last frame. Use --error-trace for full trace.
  # 
  # In tryit.cr:19:17
  # 
  # 19 | if (a = @a).empty?
  # ^-----
  # Error: undefined method 'empty?' for Nil (compile-time type is (Array(Int32) | Nil))
  def handling_nil
    @a ||= from_the_database
    if (a = @a).empty?
      @a = [2]
    end
    @a
  end

  # This one is okay
  # def handling_nil
  # @a ||= from_the_database
  # if (a = @a) && a.empty?
  # @a = [2]
  # end
  # @a
  # end
end

a = A.new
pp a.handling_nil

```

The last example in [the docs here](https://crystal-lang.org/reference/syntax_and_semantics/if_varis_a.html) suggest to me it should be fine. Am I reading something into this that I shouldn’t?

```auto
if @a.is_a?(String)
  # here @a is not guaranteed to be a String
end

a = @a
if a.is_a?(String)
  # here a is guaranteed to be a String
end

# A bit shorter:
if (a = @a).is_a?(String)
  # here a is guaranteed to be a String
end

```

My system:

```auto
$ crystal version
Crystal 1.1.0 [af095d72d] (2021-07-14)

LLVM: 10.0.0
Default target: x86_64-apple-macosx

```

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [August 27, 2021, 11:37am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/2 "2021-08-27T11:37:29Z")

</div>

Good question!

I thought it would work but apparently it doesn’t. Only the `if (a = @a).is_a?(...)` case works, you can’t use any method.

Feel free to open a feature request for this.

Thank you!

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [August 27, 2021, 11:50am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/3 "2021-08-27T11:50:49Z")

</div>

It can’t work. The conditional expression is `(a = @a).empty?`. It assigns the value of `@a` (which is nilable) to `a` and then calls a method on `a`. This method is not callable for `nil` value, so you get a compiler error. There is no expression that restricts `a` to non-nil value.

`(a = @a).is_a?` can be called because `#is_a?` is defined on `Nil`.

Another method that’s defined on `Nil` is `#try`. It’s useful for cases like these. You can call it on any nilable value and the methods block is only executed if the value is non-nil. `(a = @a). try &.empty?` returns true if the value is not nil and empty, false otherwise.

But again, this does not restrict the type of `a` to non-nil.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [August 27, 2021, 11:59am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/4 "2021-08-27T11:59:04Z")

</div>

Oh, you are right! My bad… what you said makes total sense.

---

<div class="post-metadata">

**Author:** ![yb66](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/yb66/32/739_2.png) [@yb66](https://forum.crystal-lang.org/u/yb66)\
**Post date:** [August 28, 2021, 3:49am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/5 "2021-08-28T03:49:51Z")

</div>

Thanks for the replies. They make sense but I needed to have a little think about it as I can see I’m not thinking about things in quite the right way. To be clear:

- The compiler checks are against the type, at runtime they’ll be against the value?

- `if (a = @a) && a.empty?` works because `&&` means the Nil type can’t occur on the right hand side?

Sorry if these seem blatantly obvious, I’m trying to shift my lazy thinking to the new paradigm 😅

---

<div class="post-metadata">

**Author:** ![HertzDevil](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hertzdevil/32/1023_2.png) [@HertzDevil](https://forum.crystal-lang.org/u/HertzDevil)\
**Post date:** [August 28, 2021, 5:43am UTC](https://forum.crystal-lang.org/t/nil-check-syntax-confusion/3668/6 "2021-08-28T05:43:35Z")

</div>

`&&` works because it is implemented on top of `if`:

```crystal
(a = @a) && a.empty?

# is equivalent to:

if a = @a
  a.empty? # `a` is non-nil here
else
  a
end

```
