# Why does FUNC require you to call RETURN?

**URL:** <https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576>\
**Category:** Questions\
**Created:** [November 30, 2025, 10:07pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576 "2025-11-30T22:07:57Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rebolbot](https://rebol.metaeducation.com/user_avatar/rebol.metaeducation.com/rebolbot/32/40_2.png) [@rebolbot](https://rebol.metaeducation.com/u/rebolbot)\
**Post date:** [November 30, 2025, 10:07pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576/1 "2025-11-30T22:07:57Z")

</div>

Historically in all Rebols you could just allow a function's result to drop out of the bottom:

```
rebol2>> add-twenty: func [x] [x + 20]

rebol2>> add-twenty 1000
== 1020

```

In Ren-C you get nothing (well, "TRASH!", that doesn't display in the console)

```
>> add-twenty: func [x] [x + 20]

>> add-twenty 1000

```

You have to use RETURN if you want to return the result:

```
>> add-twenty: func [x] [return x + 20]

>> add-twenty 1000
== 1020

```

I see it can be worked around, but **[doing so is harder than a casual Reboler might think](https://rebol.metaeducation.com/t/making-func-variant-that-auto-returns-last-result/2124)**:

```plaintext
func: adapt lib.func/ [
    body: inside body compose '[
        return (as group! unbind body)
    ]
]

```

While you can do that, it seems that it would be more efficient to just include a way to drop results out in the box.

Maybe FUNCTION could require a RETURN, but FUNC does not?

---

<div class="post-metadata">

**Author:** ![hostilefork](https://rebol.metaeducation.com/user_avatar/rebol.metaeducation.com/hostilefork/32/421_2.png) [@hostilefork](https://rebol.metaeducation.com/u/hostilefork)\
**Post date:** [November 30, 2025, 10:29pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576/2 "2025-11-30T22:29:46Z")

</div>

> [@rebolbot](#):
>
> Historically in all Rebols you could just allow a function's result to drop out of the bottom:

For those curious about the true history, Carl was conflicted on the matter:

[http://www.rebol.net/r3blogs/0025.html - **"Leaky Functions"**](http://www.rebol.net/r3blogs/0025.html)

* * *

> [@rebolbot](#):
>
> In Ren-C you get nothing (well, "TRASH!", that doesn't display in the console)
> 
> ```plaintext
> >> add-twenty: func [x] [x + 20]
> 
> >> add-twenty 1000
> 
> ```
> 
> Maybe FUNCTION could require a RETURN, but FUNC does not?

Use **`LAMBDA`**.

```
>> add-twenty: lambda [x] [x + 20]

>> add-twenty 1000
== 1020

```

Things to know about LAMBDA:

- It doesn't have a [definitional RETURN](https://rebol.metaeducation.com/t/what-are-definitional-returns/2191) at all. So if you execute a RETURN inside a lambda and it's not an error, that means it found _someone else's return_ to run:

- If you want to annotate LAMBDA for what it returns, the syntax is **`[]: [<typespec>`]**.

- If you don't have an interesting result, and don't want to document that by writing FUNC with **`return: [trash!]`** you can use **`PROCEDURE`** (shorthanded as **`PROC`** ):

* * *

> [@rebolbot](#):
>
> I see it can be worked around, but **[doing so is harder than a casual Reboler might think](https://rebol.metaeducation.com/t/making-func-variant-that-auto-returns-last-result/2124)**:

The fact that the specific instances of the function argument variables are not available until each function instantiation is run makes this trickier than it first appears. Binding composition is just hard to begin with, and it gets harder when the things you're binding to don't exist yet at the time of composition.

But I find it encouraging that there _are_ answers to binding problems in Ren-C (vs. just throwing up our hands and going "well, can't be done", which is pretty typical in other Redbols.)

---

<div class="post-metadata">

**Author:** ![hostilefork](https://rebol.metaeducation.com/user_avatar/rebol.metaeducation.com/hostilefork/32/421_2.png) [@hostilefork](https://rebol.metaeducation.com/u/hostilefork)\
**Post date:** [November 30, 2025, 10:41pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576/4 "2025-11-30T22:41:58Z")

</div>

> [@rebolbot](#):
>
> Historically in all Rebols you could just allow a function's result to drop out of the bottom:
> 
> In Ren-C you get nothing (well, "TRASH!", that doesn't display in the console)

So I'll mention what _actually_ happens when you reach the end of a FUNCTION without calling something that calls the definitional `RETURN*` function (or otherwise THROWs).

**the definitional `RETURN*`--if it is an ACTION!--is executed and passed -no- arguments.**

Since the default behavior of `RETURN*` with no arguments is to give back a TRASH!, that's what you get.

You can override this, and give specific behavior to the case where no argument is passed to `RETURN*` (e.g. a "hole"):

```
>> foo: func [x] [
       return*: adapt return*/ [if hole? $value [value: <small>]]
       if x > 1000 [return <big>]
   ]
        
>> foo 1020
== <big>

>> foo 304
== <small>

```

---

<div class="post-metadata">

**Author:** ![rebolbot](https://rebol.metaeducation.com/user_avatar/rebol.metaeducation.com/rebolbot/32/40_2.png) [@rebolbot](https://rebol.metaeducation.com/u/rebolbot)\
**Post date:** [December 2, 2025, 12:52pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576/5 "2025-12-02T12:52:22Z")

</div>

> [@hostilefork](#):
>
> I'm kind of starting to feel agreement with those who think it's good to be conservative about using RETURN in mid-functions. It makes the control flow harder to understand, if you can't be sure a function that entered at the top goes to the bottom.

Do there really need to be two different generators?

Couldn't FUNC(TION) act like a LAMBDA by default (or if you use a **`[]:`** return spec), but then get a definitional return if you put **`return:`** in the spec?

Maybe **`[]: []`** could also be a signal to act like PROC (no RETURN, and no result, so force to nothing).

```
foo: func [...] [...] 
; result drops out, no type check, no return

foo: func [[]: [<spec>] ...] [...]
; result drops out, typecheck, no return

foo: func [return: [<spec>] ...] [... return ...]
; panic if end reached without return, definitional return and type check

foo: func [[]: [] ...] [...]
; return trash when end reached, no return

```

---

<div class="post-metadata">

**Author:** ![hostilefork](https://rebol.metaeducation.com/user_avatar/rebol.metaeducation.com/hostilefork/32/421_2.png) [@hostilefork](https://rebol.metaeducation.com/u/hostilefork)\
**Post date:** [December 2, 2025, 12:58pm UTC](https://rebol.metaeducation.com/t/why-does-func-require-you-to-call-return/2576/6 "2025-12-02T12:58:33Z")

</div>

> [@rebolbot](#):
>
> ```plaintext
> foo: func [...] [...] 
> ; result drops out, no type check, no return
> 
> foo: func [[]: [<spec>] ...] [...]
> ; result drops out, typecheck, no return
> 
> foo: func [return: [<spec>] ...] [... return ...]
> ; panic if end reached without return, definitional return and type check
> 
> foo: func [[]: [] ...] [...]
> ; return trash when end reached, no return
> 
> ```

It would be _possible_, but it doesn't have a smooth "you get what you pay for" scale.

With FUNC as a distinct generator from LAMBDA, you're able to get a construct that offers you the ability to return any value with just

```
 func [...] [... return ...]

```

Whereas if you had to ask for it, that would add boilerplate:

```
 func [return: [any-value?] ...] [... return ...]

```

The goal is to avoid forcing you to put a type spec on if you don't have anything to say about the types yet.

**This is not to say that auto-detecting generators shouldn't exist.** In fact, I think that COMBINATOR might do exactly what you propose. So instead of there being LAMBDA-COMBINATOR and FUNC-COMBINATOR, cue it based on the presence of **`return: [...]`** or **`[]: [...]`** (probably pick lambda semantics by default if neither present).

**So maybe this case could probably work.**

> ```plaintext
> foo: func [[]: [<spec>] ...] [...]
> ; result drops out, typecheck, no return
> 
> ```

That would make it easier on anyone who wanted to write an auto-detecting generator.
