# Returning from captured block

**URL:** <https://forum.crystal-lang.org/t/returning-from-captured-block/6344>\
**Category:** Help & Support\
**Created:** [January 20, 2024, 10:55am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344 "2024-01-20T10:55:22Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![aboulafia](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@aboulafia](https://forum.crystal-lang.org/u/aboulafia)\
**Post date:** [January 20, 2024, 10:55am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/1 "2024-01-20T10:55:22Z")

</div>

Hi all, I’m strugling to grasp how blocks and yield work on recursive calls

The documentation says

> `return` and `break` can’t be used inside a captured block. `next` can be used and will exit and give the value of the captured block.

Basically I would like to have a walk function that I can use for many purposes.  
In the example below, I want to use dump() to use walk(), same for find\_first() to avoid over repeating the same walk pattern again and again

dump() is easy and ok, but find\_first() does not work and always returns nil

Obviously there’s something that I don’t understand

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

Edit : I tried another solution, still no luck [Carcin](https://play.crystal-lang.org/#/r/gdkq)

Edit 2 : I got something, but find\_first returns the last found, instead of the first one [Carcin](https://play.crystal-lang.org/#/r/gdks)

---

<div class="post-metadata">

**Author:** ![aboulafia](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@aboulafia](https://forum.crystal-lang.org/u/aboulafia)\
**Post date:** [January 20, 2024, 11:39am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/2 "2024-01-20T11:39:31Z")

</div>

Ok I got it working, but I find my code very weird - How can it be improved ?

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

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [January 20, 2024, 1:05pm UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/3 "2024-01-20T13:05:01Z")

</div>

Since I often ask many questions here, I wanted to contribute by providing some answers. However, I couldn’t write them myself, so I had GPT-4 write the code for me. Especially the show method is the work of ChatGPT, I had nothing to do with it.

```cr
class Node
  getter children : Array(Node)
  getter name : String

  def initialize(@name : String)
    @children = [] of Node
  end

  def add(child : Node)
    @children << child
  end

  def walk(&block : Node ->)
    block.call(self)
    @children.each { |child| child.walk(&block) }
  end

  def find(&block : Node -> Bool)
    result = nil
    walk { |node| result ||= node if block.call(node) }
    result
  end

  def find_all(&block : Node -> Bool)
    matches = [] of Node
    walk { |node| matches << node if block.call(node) }
    matches
  end

  def inspect
    "Node(#{name})"
  end

  def show(indent = 0, is_last = true, prefix = "")
    result = "#{prefix}#{is_last ? "└─ " : "├─ "}#{name}\n"

    @children.each_with_index do |child, index|
      child_prefix = is_last ? " " : "│ "
      result += child.show(indent + 2, index == @children.size - 1, prefix + child_prefix)
    end

    result
  end
end

root = Node.new("root")
child1 = Node.new("c1")
child2 = Node.new("c2")
child3 = Node.new("c3")

child1.add(child2)
child1.add(child3)

root.add(child1)

p! child1
pp child2

puts root.show

found = root.find { |n| n.name == "c2" }
puts "Found: #{found.inspect}"

```

I have been using Crystal for 2 years and have not noticed a big difference between captured blocks and inline blocks…

---

<div class="post-metadata">

**Author:** ![aboulafia](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@aboulafia](https://forum.crystal-lang.org/u/aboulafia)\
**Post date:** [January 20, 2024, 1:21pm UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/4 "2024-01-20T13:21:34Z")

</div>

Wheeez, this code is far more better than I could have writen myself (at least for now)

I’m might add that I’m using GPT3.5 (free) which could not help me, or may be I wrongly prompted

Is it frightening ?

Thanks @kojix2

---

<div class="post-metadata">

**Author:** ![aboulafia](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@aboulafia](https://forum.crystal-lang.org/u/aboulafia)\
**Post date:** [January 20, 2024, 1:22pm UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/5 "2024-01-20T13:22:50Z")

</div>

> [@kojix2](#):
>
> captured blocks and inline blocks…

Could you explain the difference between the two ? Are captured those using yield and inline those using call() ?

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [January 20, 2024, 1:53pm UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/6 "2024-01-20T13:53:56Z")

</div>

Actually, the behavior of `walk` and `find` is different in the new code compared to the original code.

- `walk` only moves nodes.
- `find` accepts blocks that return boolean values. This is equivalent to the original `walk`.

This is a typical Ruby/Crystal API. ChatGPT does not change the behavior of the original method unless you explicitly tell it to. Human experience is required here 🙂

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [January 20, 2024, 2:01pm UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/7 "2024-01-20T14:01:58Z")

</div>

If we could use `return` inside the captured block we could have written

```auto
def find
  walk { |node| return node if yield }
end

```

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [January 21, 2024, 10:36am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/8 "2024-01-21T10:36:26Z")

</div>

your last example (Edit2) almost works. The only mistake is that `next` returns nil, you have to do `next r`:  
[https://play.crystal-lang.org/#/r/gdry](https://play.crystal-lang.org/#/r/gdry)

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [January 21, 2024, 10:53am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/9 "2024-01-21T10:53:08Z")

</div>

> [@aboulafia](#):
>
> Could you explain the difference between the two ? Are captured those using yield and inline those using call() ?

opposite:  
inline blocks use `yield`. Basically, compiler copy-paste content of block instead of `yield` keyword. This is more effective than capturing so should be preferred when possible.  
Captured blocks means that compiler saves block to a closured function and `call`s it when needed.

---

<div class="post-metadata">

**Author:** ![aboulafia](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@aboulafia](https://forum.crystal-lang.org/u/aboulafia)\
**Post date:** [January 21, 2024, 11:31am UTC](https://forum.crystal-lang.org/t/returning-from-captured-block/6344/10 "2024-01-21T11:31:35Z")

</div>

> [@konovod](#):
>
> The only mistake is that `next` returns nil, you have to do `next`

I didn’t think about it, but it totally makes sense in this context - next r behaves “like” a return r,  
Thanks to pointing out !
