[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: A bit more fft. Was Re: Ambiguous Syntax (was Re: Free format strings?)
- From: RLake@...
- Date: Tue, 14 Jan 2003 16:23:29 -0500
> Luiz Henrique de Figueiredo:
>> You're right about "return". The limitation on "break" is because we
>> wanted to leave the possibility of adding break labels in the future
>> (although I don't think we will).
That's a shame, sort of
> It's probably all for the good to keep the Return & Break limitations
> consistent with each other even if it's not actually needed
This has always puzzled me. Under what circumstances would you want to
put a statement after return or break? It could not possibly be executed,
and I'm quite happy to have the syntax checker tell me that.
While we're dreaming, I'll put in my plug again for non-local exits,
Dylan-style, instead of break labels and exceptions. The idea is
begin name chunk end
is an expression (not a statement) in which "name" is locally defined as
a first-class continuation with the restriction that it cannot be used
after the begin block is exited. However, it can be passed as an argument.
That is, name is defined as a function with a variable number of arguments;
calling it causes the begin block to evaluate to those arguments.
You can implement both break and return with this mechanism, not that I
am suggesting that but it is an interesting observation.
The implementation should be fairly straightforward in Lua 5; restricted
continuations do not require complex stack manipulation and I would have
thought that a mechanism similar to the one used to heapify upvalues
would also serve to nullify continuations on block exit. I think this is
consistent with the Lua philosophy: provide a simple powerful
infrastructure and let people use it.
Simple example, just for illustration:
Say we have:
function tree_walk(t, condition, dothis)
if t then
tree_walk(t.left, condition, dothis)
if condition(t) then dothis(t) end
tree_walk(t.right, condition, dothis)
return t.type == "variable"
Now, obviously we can say:
tree_walk(t, is_variable, print_node)
But the non-local exit also gives a nice solution to this:
return begin gotit
tree_walk(t, is_variable, gotit)
Clearly this could also implement exceptions. But it is significantly more
than exceptions because it provides for an "exception handler" that doesn't
the stack. Sometimes, for example, you can correct for an exceptional
and you just want to continue. Dylan handles this by binding exception
with functions; the function is called when the exception happens. If the
can handle it, it could accept a return value and retry the computation;
it is also possible to bind the condition to a non-local exit and achieve
Pseudo example with pseudo syntax:
local function giveup(filename)
log_error(filename .. " was not found, Cannot continue\n")
local function prompt_for_filename(filename)
new_filename = gui.file_dialog(filename ..
"was not found, which file should I use?")
return new_filename or giveup(filename)
-- this is the key line, like a try/catch but different
with file_not_found_error = (interactive and prompt_for_filename) or
input = io.open(fn)
-- io.open pseudo-code:
while "we haven't succeeded" do
local file = system.open(filename)
if file then return file end
if system.error == ENOENT then
filename = file_not_found_error(filename)
-- more error tests
Side note: the above requires dynamically local variables; that is, the
with statement does not create a new local called file_not_found_error;
rather, it saves the old value of the global and temporarily resets it to
the value of the expression. On exit, it has to restored the saved value,
even with a non-local exit. I don't think that is too difficult to
implement either, but it does add a bit of bulk.