How Attached are we to Functions Return Last Result?

In JavaScript, the failure to specify a RETURN statement is basically the way of saying you don't return anything. Functions don't accidentally leak values, you just get undefined:

> function nada() { 1 + 2; }

> nada()
<- undefined

> function three() { return 1 + 2; }

> three()
3

I know this isn't how Rebol has historically operated. But the historical operation of Rebol can lead to the accidental leakage of a lot of values which the caller wasn't necessarily meant to see. There's currently a burden to annotate in the spec when a function doesn't return something (the <void>).

So in the "Let's not give JavaScript any upper hand" line of thinking, should this be re-evaluated? I must admit I kind of feel their way is clearer. :-/

1 Like

If return comes, make it optional. The current behaviour is fine by me. Adding return is undoing part of REBOL way, REBOL takes care of taking and returning the last result. If you like it or not. It is not the end-user but the programmer that has to deal with it and the programmer should be able to handle or use PHP or Java instead.
Having the function return without declaring variables or having to specify a RETURN statement is very useful in quicky programming.

This could also be another construct. MACRO perhaps, or INLINE...where the idea is to create something that substitutes an expression.

>> foo-macro: macro [x y] [append x y]
>> foo-macro [a b c] 'd
== [a b c d]

>> foo-function: function [x y] [append x y]
>> foo-function
; no result (e.g. void!)

Or something. I dunno, I think it's worth asking if it's a great idea to leak by default. I personally like the RETURN making it clear whether something is actually meant to be a return result...it can be hard to tell when looking at:

foo: function [...] [
    ...
    ...
    something-or-another
]

Is that intentionally returning the result of something-or-another? Or is that a function intended to have a side effect, whose result is not part of the contract?

1 Like

Very.

To me it is part of what defines Rebol. Every function which doesn't return anything disturbs the flow for me, and breaks the ability to chain functions together.
It is part of the programmers responsibility to return something sensible.
(Well, this is my opinion at least.)

1 Like

I have to read and maintain a lot of code (including things like the wild Rebmake), as well as even odd things I've written. I really find that it can be bewildering on a function that has no RETURN: documentation and some weird expression in the last slot to know if that thing is used by any callers.

My opinion here is that having a return-or-not is a big leg up in understanding the reach of a function, and whether you can reorganize it (or add more code to the end) without breaking something.

But as I've outlined in Implicit Execution of Return in Functions, this goes further than just our preferences for readability. Because RETURN is a function itself, we're in different territory...and it's a territory I want people to be able to explore with doing things like hooking the RETURN function and customizing it.

There will be two options:

  • Use LAMBDA. Lambda is known in languages for a construct that does substitution of the results of a parameterized expression and doesn't need RETURN.

    • One feature of lambda is that it does not have RETURN of its own. This makes it useful for block branches and other services inside the context of another function.

    • If you decide at some point you do want a RETURN, you will have to promote your code to a FUNC(TION) and add a RETURN on all paths--including what drops out the bottom.

  • Go your own path and define FUNC to RETURN its body as a group:

    func: adapt :func [
        body: compose [return (as group! body)]
    ]
    

    People should give deep thought to whether the toolbox of definitions they import into every project should override fundamental behaviors. But if you find something is a closely held belief, then do it.

I must admit that this makes some sense. So I hope this'll lead to more conscious decisions on what to return.

2 Likes

Yes, having function that have a none as closing statement, to make sure the function does not return something.

It's true that you could adopt a reverse convention, by which any function that doesn't have a meaningful return result ends just saying none.

But the problem with conventions is that not everyone follows them.

I'll maintain that the best answer here is for me to do what's "right" by the architecture and my senses, and encourage people to be as "wacky as they want to be" by making their own box-of-tools they import on whatever scripts they write.

And really, your script probably shouldn't have a lot of "FUNC" in them anyway. Each task should probably have you quickly dialecting a layer suited to the task, and you should quickly climb higher than FUNC.

I think this is the philosophy of the language--if you're not bending it, you're probably not really using it. Each script should have a setup which does the bends that suits the task, and anyone reading the script should take note of that being the context they're operating in. With module isolation working properly, this becomes practical for each and every script to rip things up arbitrarily.

My job is to make sure it can bend, and I'm doing a good job. :slight_smile:

2 Likes