# In case statement, case nil and range

**URL:** https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623
**Category:** Help & Support
**Created:** [October 15, 2020, 4:34am UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623 "2020-10-15T04:34:02Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![nemorami](https://avatars.discourse-cdn.com/v4/letter/n/eb9ed0/32.png) [@nemorami](https://forum.crystal-lang.org/u/nemorami)
#### Post date: [October 15, 2020, 4:34am UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/1 "2020-10-15T04:34:02Z")

</div>

this code doesn’t compile.

```crystal
ch = nil
case ch
when 'A' .. 'Z'
  puts "ch is capital"
when Nil
  puts "ch is nil"
end

```

In case statement, if no range expression, it is compiled successfully.

---

<div class="post-metadata">

### Author: ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)
#### Post date: [October 15, 2020, 4:43am UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/2 "2020-10-15T04:43:56Z")

</div>

Put the `when Nil` first, would be the easiest way to fix this.

---

<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: [October 15, 2020, 12:06pm UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/3 "2020-10-15T12:06:32Z")

</div>

It’s a bug, please report it. Thank you!

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [February 20, 2023, 10:07am UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/4 "2023-02-20T10:07:05Z")

</div>

Following code still not work on 1.7.2, any one report bug on this?

```auto
ch : Char? = nil

case ch
when 'A'..'Z'
  puts "ch is capital"
when Nil
  puts "ch is nil"
end

```

```auto
In 1.cr:13:6

 13 | when 'A'..'Z'
           ^-
Error: instantiating 'Range(Char, Char)#===(Nil)'

In /home/zw963/Crystal/share/crystal/src/range.cr:327:5

 327 | includes?(value)
       ^--------
Error: instantiating 'includes?(Nil)'

In /home/zw963/Crystal/share/crystal/src/range.cr:298:32

 298 | (begin_value.nil? || value >= begin_value) &&
                                  ^
Error: undefined method '>=' for Nil

Nil trace:

  /home/zw963/Crystal/share/crystal/src/range.cr:298

        (begin_value.nil? || value >= begin_value) &&

  /home/zw963/Crystal/share/crystal/src/range.cr:293

      def includes?(value) : Bool

```

---

<div class="post-metadata">

### Author: ![npn](https://avatars.discourse-cdn.com/v4/letter/n/e68b1a/32.png) [@npn](https://forum.crystal-lang.org/u/npn)
#### Post date: [February 20, 2023, 1:28pm UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/5 "2023-02-20T13:28:52Z")

</div>

because it is not really a bug.

the `switch case ...` block is translated to a series of `if ... then ... elsif ... then ...`.  
another feature of crystal is can predict what a variable is null or not, by using `if` guard.

So if you put `when Nil` first if will be translated to:

```auto
if ch.is_a?(Nil)
...
else # we know that ch is not nil, thus `Char` here
....

```

I guess the compiler can be a little smarter to always put Nil on top of the expanded expression, but this is unexpected and can create subtle bugs for someone who expect the conditions match sequentially.  
So unless we can make sure that Nil condition can be put at top without causing any problem it’s better not doing anything.

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [February 20, 2023, 2:36pm UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/6 "2023-02-20T14:36:16Z")

</div>

Thanks, this error raised by following translated code.

```auto
if ('A'..'Z') === ch
  puts "ch is capital"
elsif Nil === ch
  puts "ch is nil"
end

```

Maybe we should mention this in our `syntax_and_semantics/case.html`, because this is still a surprise, This is also what the Ruby tries to avoid (matz’s principle of least surprise)

We should always check Nil out of case statement. e.g. like this:

```crystal
ch : Char? = nil

if ch.nil?
  puts "ch is nil"
else
  case ch
  when 'A'..'Z'
    puts "ch is capital"
  when others
    # ...
  end
end

```

---

<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: [February 20, 2023, 3:22pm UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/7 "2023-02-20T15:22:08Z")

</div>

This is bug. Could you report it please? Thank you!

To clarify, the code should compile just fine. `===` must return `nil` if it can’t match the value, never give a compilation error.

---

<div class="post-metadata">

### Author: ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)
#### Post date: [February 20, 2023, 3:36pm UTC](https://forum.crystal-lang.org/t/in-case-statement-case-nil-and-range/2623/8 "2023-02-20T15:36:50Z")

</div>

> <https://github.com/crystal-lang/crystal/issues/13094>
>
> \## Bug Report
> 
> For more details, check discuss on https://forum.crystal-lang.o…rg/t/in-case-statement-case-nil-and-range/2623/2
> 
> Following code not work on Crystal 1.7.2
> 
> \`\`\`
> ch : Char? = nil
> 
> case ch
> when 'A'..'Z'
> puts "ch is capital"
> when Nil
> puts "ch is nil"
> end
> \`\`\`
> \<details\>
> \<summary\> Click me to see back trace \</summary\>
> 
> \`\`\`
> In 1.cr:13:6
> 
> 13 | when 'A'..'Z'
> ^-
> Error: instantiating 'Range(Char, Char)#===(Nil)'
> 
> 
> In /home/zw963/Crystal/share/crystal/src/range.cr:327:5
> 
> 327 | includes?(value)
> ^--------
> Error: instantiating 'includes?(Nil)'
> 
> 
> In /home/zw963/Crystal/share/crystal/src/range.cr:298:32
> 
> 298 | (begin\_value.nil? || value \>= begin\_value) &&
> ^
> Error: undefined method '\>=' for Nil
> 
> Nil trace:
> 
> /home/zw963/Crystal/share/crystal/src/range.cr:298
> 
> (begin\_value.nil? || value \>= begin\_value) &&
> 
> 
> /home/zw963/Crystal/share/crystal/src/range.cr:293
> 
> def includes?(value) : Bool
> \`\`\`
> 
> \<details\>
> 
> I guess this error raised because compiler translate above code into following:
> 
> \`\`\`
> ch : Char? = nil
> 
> if ('A'..'Z') === ch
> puts "ch is capital"
> elsif Nil === ch
> puts "ch is nil"
> end
> \`\`\`
> 
> \`===\` in \`('A'..'Z') === ch\` must return nil if it can’t match the value, never give a compilation error.
