[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Features to remove: return and noreturn
[this is a reply to Harald's note about removing return and $&noreturn.]
I understand that $&noreturn is a relatively new feature of the es
landscape, so I'll probably attract a lot of flamage when I propose to
get rid of it.
probably not. if there's anything in the language that stands out
as a hack, it's $&noreturn. i'm very unhappy with it.
Not only that, I'll propose to throw away return as
well! Don't get out the old flame throwers yet -- please listen me
out -- the reason is this: There is already a perfectly decent catch
and throw mechanism in place; and the return mechanism is nothing but
using throw with the extra magic that functions capture thrown
returns. Unless of course they are being run with $&noreturn. I find
this kludgy and confusing.
It can also cause subtle errors:
[ example omitted. ]
Now, of course I do not intend to force the user to deal with raw
catch and throw. All we need is a convenience function. I'd call it
tag, but other suggestions are welcome:
fn tag name cmd {
catch @ e x {if {~ $e $name} {result $x} {throw $e $x}} \
{local (fn $name x {throw $name $x}) $cmd}}
Now, local and non-local returns are handled in exactly the same way,
namely by tagging the function and by using the tag to return values.
For example, here is a function that given three arguments will return
one of them if the two other are equal:
fn f a b c {
tag retvrn {let (g = @ a b c {if {~ $a $b} {retvrn $c}})
{$g $a $b $c; $g $b $c $a; $g $c $a $b; result}}}
At the minimal price of declaring the return tag, the user is given
the freedom of not having to worry about the number of levels his
returns have to ascend.
there's a lot to this proposal, and i'm sorry it took me so long
to reply to it. i'm still not entirely sure about how i feel.
this reply is basically just a set of thoughts that are not as
coherent as i'd like.
(a) return is only half of the problem. break is the other half.
as far as i'm concerned, getting rid of return implies getting
rid of break. (i don't think that's necessarily a bad thing.)
(b) i think that this tag function is potentially very useful, and
people should probably consider adding it or something similar to
their set of tools for working with es. perhaps with some
experience with tag it should be added to the default initial.es,
but only after we've played with it and alternatives.
(tag is now in my autoload directory.)
(c) tag doesn't, however, address the fundamental problem with
break and return, which is that they have completely dynamic
behavior, and don't follow lexical scope. if you use the
same tag name in two places, you have exactly the same problem
as you do with break or return.
(d) John and Scott were right in critizing es back in october for
(1) not having first-class continuations
(2) using first-class continuations for break/return
nonetheless, continuations are hard to implement (or, at least,
hard to retrofit) and ``it's not going to happen'' for pre-1.0 es.
(e) if Harald had written this back then, i probably would have said
something like ``what you really want is something like an escape
continuation for the function lexically bound to a function named
return (or break) for the body of the lambda (or loop).''
(f) experience with es and it's exception mechanism, however, tells
me that (e) is not what i want now. in particular, continuations
have this nasty way of bypassing things like unwind-protect, which
is wrong, in my (current) opinion. (perhaps that means that the
exception stuff should go away, but i like that idea less.)
(g) what i think i want, at the moment, is the current dynamic behavior,
except that break and return would be bound lexically over their
bodies to things like
throw break while-0x12345678
where the word after the word ``break'' in the exception would be
a unique (or ``unique-enough'') tag that would allow the ``right''
catch routine to catch the tag, and all others to ignore it.
(h) unfortunately, since while is not syntax, (g) is hard to do. (not
that there aren't workaround, but i don't like the ones i've come
up with yet.)
(i) as a side note, es only has an exception mechanism because, when
we were designing es, we pulled rc's internal exception mechanism
out to user level, in order to support break and return. when we
first thought of it, we didn't really expect to use the exceptions
for anything but them. i find this slightly ironic.
for now, nothing's going to change. i want to know what other people think.
something may appear between 0.88 and 0.89 that looks somewhat like (g).
now, back to Harald's note:
Besides, I would assume that many present
uses of return could easily be replaced with result, perhaps after
some rewriting:
fn foo { fn foo {
if {test} {return bar} --> if {test} {result bar} {
blah blah ...} blah blah ...}}
true. i would encourage people to use result instead of return when
it makes sense to.
paul