# Guessing type over proc

**URL:** <https://forum.crystal-lang.org/t/guessing-type-over-proc/2406>\
**Category:** Help & Support\
**Created:** [August 2, 2020, 6:55am UTC](https://forum.crystal-lang.org/t/guessing-type-over-proc/2406 "2020-08-02T06:55:28Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![lugia-kun](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/lugia-kun/32/235_2.png) [@lugia-kun](https://forum.crystal-lang.org/u/lugia-kun)\
**Post date:** [August 2, 2020, 6:55am UTC](https://forum.crystal-lang.org/t/guessing-type-over-proc/2406/1 "2020-08-02T06:55:28Z")

</div>

This code fails to compile because the type of `t` is just `Nil` and it does not have `#[]` at the first  
type reduction, I think.

```crystal
def foo(&)
  t = nil
  (1..10).each do |i|
    t = yield(t, i)
  end
  t
end
 
ret = foo do |t, i|
  a = -> do
    { a: i, b: (t ? t[:b] : nil) }
  end
  b = -> do
    { a: (t ? t[:a] : nil), b: i }
  end
  if rand > 0.2
    a.call
  elsif rand > 0.2
    b.call
  else
    t
  end
end
 
pp! ret

```

```auto
Showing last frame. Use --error-trace for full trace.

error in line 11
Error: undefined method '[]' for Nil

```

[https://play.crystal-lang.org/#/r/9hd0](https://play.crystal-lang.org/#/r/9hd0)

But, the following code which same except without proc compiles fine.

```crystal
def foo(&)
  t = nil
  (1..10).each do |i|
    t = yield(t, i)
  end
  t
end
 
ret = foo do |t, i|
  if rand > 0.2
    { a: i, b: (t ? t[:b] : nil) }
  elsif rand > 0.2
    { a: (t ? t[:a] : nil), b: i }
  else
    t
  end
end
 
pp! ret

```

```auto
ret # => {a: 10, b: 1}

```

[https://play.crystal-lang.org/#/r/9hd2](https://play.crystal-lang.org/#/r/9hd2)

What is different here?

---

<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 2, 2020, 12:26pm UTC](https://forum.crystal-lang.org/t/guessing-type-over-proc/2406/2 "2020-08-02T12:26:46Z")

</div>

The difference is that a `Proc` captures the variables that exist outside of them. When this happens, the compiler can’t know when the Proc is going to be called, and whether the variable is going to change.

You are looking for [this bug](https://github.com/crystal-lang/crystal/issues/3093) which is not going to be fixed anytime soon.

The workaround is to assign `t` to another variable inside the `Proc`:

```crystal
def foo(&)
  t = nil
  (1..10).each do |i|
    t = yield(t, i)
  end
  t
end

ret = foo do |t, i|
  a = ->do
    t2 = t
    {a: i, b: (t2 ? t2[:b] : nil)}
  end
  b = ->do
    t2 = t
    {a: (t2 ? t2[:a] : nil), b: i}
  end
  if rand > 0.2
    a.call
  elsif rand > 0.2
    b.call
  else
    t
  end
end

pp! ret

```

---

<div class="post-metadata">

**Author:** ![lugia-kun](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/lugia-kun/32/235_2.png) [@lugia-kun](https://forum.crystal-lang.org/u/lugia-kun)\
**Post date:** [August 2, 2020, 3:29pm UTC](https://forum.crystal-lang.org/t/guessing-type-over-proc/2406/3 "2020-08-02T15:29:29Z")

</div>

Thanks. I got it.

So, `proc` captures variables by their names on the scope of defining.  
I thought that `proc` captures the referencing objects of variables used inside.

I’m also going to note this: I found [this comment](https://github.com/crystal-lang/crystal/issues/4168#issuecomment-287789738) from the given link which describes why type check `(t ? t[:b] : nil)` does not work as expected.
