hlovatt schrieb:
> On Oct 21, 12:40 pm, "Neal Gafter" <[EMAIL PROTECTED]> wrote:
>> A new exception hierarchy outside Throwable is necessary for closures to
>> satisfy Tennent's Correspondence Principle, which as you know is a powerful
>> litmus test for the expressive power of a language feature such as closures.
> 
> Tennent used his Principle of Correspondence to argue against return,
> break, and continue and instead advocated that every block should have
> one exit point (end of block). 

sorry for warming up this thread after a week...
It is a shame that I not yet had a chance of reading this... but maybe 
you can answer some questions.

For example how did he define exit point? for example in this case

def foo() { throw new RuntimeException("something") }

while (true) {
   foo()
}

you said "end of block", so I guess it has only one exit point... or 
does the foo() method have two then? If yes, wouldn't mean that 
exceptions are bad in Tennent's Correspondence Principle?

But ok, let us say this has only one exit point.... Now, if we have a 
list and we want to proceed all elements until we meet a certain element 
and then stop processing, then I would write something like this:

for (XY element : list) {
    if (element==myBreakCondition) break
    doSometing(element)
}

this has (at last) two exit point because of the loop, so I guess I 
would have to change the loop condition to do the additional check

XY element
for (Iterator it=list.iterator();
      it.hasNext() && element!=myBreakCondition;) {
   element = it.next()
   doSomething(element)
}

but in case of a "closure" I could do this:

list.each { XY element, LoopFlow flowControl ->
   flowControl.breakIf(element==myBreakCondition)
   doSometing(element)
}

where flowControl.breakIf would throw an exception, each (I will call 
each an iteration method, because it iterates over the list here) would 
catch that exception and use flowControl to check the exception... Would 
this still fulfill the "only one exit point per block" idea?

Or the next question... if we say that a "closure syntax" overlaps with 
the syntax generally used by blocks, but if the "closure" is no block... 
does the principle then still apply to break/continue which have to be 
applied to the iteration method?

Or let us say a break statement is not allowed in a "closure".. what 
does the principle say to this? I mean having one exit point per block 
is easily fulfilled with that, because it would not compile... Is the 
language to be considered as "less expressive" then, even if the break 
statement can be expressed by other elements that are not of syntactic 
nature? Or if I had a different syntactic element to do a break in a 
closure.. would the language then still be considered as "less powerful"?

[...]
> Having said that the block must be named, then the standard exception
> mechanism can be used and this has the added advantage of providing a
> compile time check for asynchronous use cases, e.g.:
> 
> // in the example below method { .. } is suggested short syntax for an
> inner class (closure)
> int i = 0;
> iLoop: while ( true ) {
>   invokeLater( method { ...; break iLoop; ... } ); // Error since
> invokeLater doesn't catch iLoopBreakException
>   }
> }
 >
> The above example is caught at compile time because when expanded the
> object passed to invokeLater throws a checked exception, iLoopBreak,
> which isn't caught (and can't be caught because it is a local class)
> by invokeLater. See previous return example for how break etc. are
> expanded.

on the other hand.... why is that a illegal usage of "break iLoop"? I 
mean ok, invokeLater might execute the "closure" in a different Thread, 
but what if not?

I guess that's why the closure proposal expects the usage of "for" here:

l1: while (true) {
   l2: for each(element:list) {
      if (element == myBreakCondition) break l1
      break l2
   }
}

from a pragmatic point of view I guess you would have to tell your 
iteration method that it needs to respond to "break l2", but not to 
"break l1". But of course I can not write:

void for each(List list, MyClosure closure, Label label) {
   label: for (x : list) closure.call()
}

and you can get even more fun with something like:

l1: while (true) {
   l2: for each(element:list) {
      check (element == myBreakCondition, {break l1})
      break l2
   }
}

which means that check should execute the closure {break l1} if 
element==myBreakCondition. If we use the interface coercion that was 
proposed, then we would have to throw an compile time error here if the 
interface (for example Runnable) does not throw that exception. Or not? 
I mean according to your text above it must, because Runnable does not 
throw that exception and check would have to throw that exception too. 
But the advantage of the "for" keyword usage seems to be kind of lost here.

So from looking at this from the perspective of a static type system 
where I want to have compile time checks as much as possible a checked 
exception would make sense to me. From the perspective of a API writer I 
get horrified but that ideas, because it means any method that somehow 
has to handle "closures" containing a break/continue would have to throw 
the exception. It would be equally annoying to he RemoteException for 
example. On the bytecode level it makes no difference, because the JVM 
is not checking if a exception is checked or not, only the Java compiler 
does.

Regardless if new exception type is defined or not, I guess the API 
writers still get exposed to an implementation detail if they want to 
have their custom iteration methods which I think is bad...

And even if there is a way to express the each without letting it 
explicitly catch and evaluate the exception (I would really like to know 
how to get around that), a checked exception would still mean, that at 
some point any API writer gets exposed to this implementation detail 
when they use the iteration method on their own.

> I would also caution that adding support for non-local returns will
> probably not be worth the trouble, since I doubt that non-local
> returns will be used much. For example, what is a good use case
> (remember that many languages don't have return etc. at all)?

so you have no problem with break, but with return? I hope my check 
method example above did show you that it is not only "return", it is 
also break/continue to some extend.

bye blackdrag

-- 
Jochen "blackdrag" Theodorou
Groovy Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/
http://www.g2one.com/

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/jvm-languages?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to