<Note: These are some remarks I made to MarkM in a correspondence I had with him earlier today as I was giving him some feedback on his draft FC'00 paper. He suggested that as thse concerns the language design in general rather than the paper in particular, I ought to share them more broadly, so here (in slightly edited form) they are.>
define factorial(n) {
^if (n <= 0) {
^1
} else {
^n * factorial(n-1)
}
define factorial(n) {
if (n <= 0) {
^1
} else {
^n * factorial(n-1)
}
is just wrong. I would expect it to (a) throw an exception (effectively crashing the program in this example), (b) silently do something wrong (very bad), or (c) get caught by the compiler (which will feel to the programmer like one of those pedantic complilation errors where the compiler is objecting to some purely formal deviance rather than to something substantive, the kind of error where you tend to think "hey, if the compiler knew *that*, why didn't it just do the right thing?" -- never mind that the right thing isn't actually 100% obvious, that's what programmers will think).
I understand that this is trying to make revelation explicit, presumably so that it becomes a deliberate act (for example, so that a function does not inadvertantly reveal information that was not meant to be revealed, simply because that information happened to be the last thing computed). That's a laudable goal, but I suspect the mechanism will prove cumbersome. Falling back on the custom of using the value of the last expression in a block as the value of the block seems to me a more pragmatic design. If we need to have an explicit value that denotes a non-result for the "I'm not really returning anything" case, that's OK with me.