Today I tried to write (approximately) this code in Java:
//Java
Scope scope = declaration.getContainer();
do {
if (scope.getDirectMemberOrParameter(model.getName())!=null) {
node.addError("duplicate declaration name: " + declaration.getName());
}
boolean isControlBlock = scope instanceof ControlBlock;
scope = scope.getContainer();
}
while (isControlBlock); //compile error
This didn't work, since Java doesn't consider the while condition expression to belong to the do block. I think this is wrong. Surely the loop should be allowed to compute it's own termination condition? I realize that do/while is a fairly uncommon construct, but when it is used, I imagine it's pretty common that it would be used like this.
The only reasonable way to fix the above code is to move the declaration of isControlBlock outside the loop:
//Java
boolean isControlBlock;
Scope scope = declaration.getContainer();
do {
if (scope.getDirectMemberOrParameter(model.getName())!=null) {
node.addError("duplicate declaration name: " + declaration.getName());
}
isControlBlock = scope instanceof ControlBlock;
scope = scope.getContainer();
}
while (isControlBlock);
Note that isControlBlock is now a variable. I would not be able to declare it final.
The Ceylon type analyzer accepts the equivalent code:
//Ceylon
variable local scope = declaration.container;
do {
if (scope.directMemberOrParameter(model.name) exists) {
node.addError("duplicate declaration name: " + declaration.name);
}
local isControlBlock = scope is ControlBlock;
scope = scope.container;
}
while (isControlBlock);
I'm going to clarify that this is allowed in the language specification.
Tags: Ceylon
Created: 17. Jul 2011, 21:08 CET (Gavin King)
Last Modified: 18. Jul 2011, 05:28 CET (Gavin King)
I don't agree that what you say should be... if you can declare the while condition inside the loop.. there could be a condition tied to it being declared in the loop that could cause it not to be declared. Declaring it outside the loop makes sense.
@jilaz: that doesn't make sense, if a condition could cause it not to be declared (I don't that's actually possible, but let's leave it at not being initialized) then the same thing could happen outside the loop. Like always your code has to make sense for it to work.
Huh? What's wrong with the code that I originally tried to write, and how do you think it should have been written? Surely the first version of the code (the one that didn't compile) is better than the second version that does compile, right?
Ah, now I think I understand what you're trying to say. I think that when you wrote , you meant to write . This interpretation of your comment has the advantage that your comment would now makes sense, but the unfortunate disadvantage that it would also be incorrect. ;-)
Declaring the variable outside the loop absolutely does not guarantee that it is definitely initialized by the time you get to the while condition. What guarantees that is Java's (or Ceylon's) definite assignment analysis, which works no matter where the variable is declared. Indeed, declaring the variable inside the loop is even better from this point of view, since definite assignment analysis in that case guarantees that the variable is assigned in every iteration of the loop, and that you aren't seeing garbage values from previous iterations.
So in fact the exact opposite of what you wrote is correct! (Assuming I have the correct interpretation of your comment.)
I also find it sad that do { .. } while(..) in Java can rarely be used because of this problem. Another problem is that many loops end up as follows:
while (true) { int x = read(..); if (x < 0) { break; } }Another problem if I can't often use the enhanced for loop because I also need a counter (do something starting with the second iteration). I would prefer if loops are simpler. What about:
// while (x < 10) process(x); loop while x < 10 process x // while ((x = read()) >= 0) process(x); loop x := read() until x < 0 process x // do { process x; } while (x >= 0); loop process x x = next() until x < 0 // for (int x = 0; x < 10; x++) process(x); loop x while x < 10 process x // for (int x = 10; x > 0; x--) process(x); loop x := 10; x-- while x > 0 process x // for (int x = 2; x < 10; x+=x) process(x); loop x := 2; x += x while x < 10 process x // for (String s : list()) process(s); loop x : list() process x // for (x : y.list()) { i++; } loop i, x : list() process x // for (int i = 0, size = list.size(); i < size; i++) loop i, size = list.size while i < sizeSo that all loops start with , there is an optional loop variable, and you can break for a loop using and . Something like this.
I would really like to see an enhanced-for-loop with a counter. I often use the classic for loop just because I need the index.
Did you say that you would like a loop condition to depend on the value of a final variable??
I like the idea of defining the terminating condition with the block itself, however I find the syntax that your proposing is odd.
When I see this
variable local scope = declaration.container; do { if (scope.directMemberOrParameter(model.name) exists) { node.addError("duplicate declaration name: " + declaration.name); } local isControlBlock = scope is ControlBlock; scope = scope.container; } while (isControlBlock);What throws me off is that the while condition is evaluating a value that is defined within a that the while condition is not in.
I personally find that odd, and unlike other programming structures that I'm familiar with, and I'm not aware of any other language doing the do..while loop in that manner (not that that's a bad thing)
Since you are writing the definition of a language, why include a do.. while ? Why not do something completely different like
variable local scope = declaration.container; repeat { if (scope.directMemberOrParameter(model.name) exists) { node.addError("duplicate declaration name: " + declaration.name); } local isControlBlock = scope is ControlBlock; scope = scope.container; exit(isControlBlock); }That's an interesting idea. Something similar is possible with Java:
for (Entry<Integer, String> e : indexed(list)) {
System.out.println(e.getKey() + ": " + e.getValue());
}
for (Entry<Integer, String> e : indexed("Hello", "World")) {
System.out.println(e.getKey() + ": " + e.getValue());
}
for (Entry<Integer, Character> e : indexed("Hello".toCharArray())) {
System.out.println(e.getKey() + ": " + e.getValue());
}
static <T> Iterable<Entry<Integer, T>> indexed(Iterable<T> t) {
return new IndexIterable<T>(t);
}
static <T> Iterable<Entry<Integer, T>> indexed(T... t) {
return new IndexIterable<T>(Arrays.asList(t));
}
So I agree it's not really required to provide support for this in the language, because it can be supported in a library.
Who says it's not in the scope of the do block? That's just what the Java language spec decided to arbitrarily define. As far as Ceylon is concerned, the scope defined by a do block extends to the while. And why the hell not? The do and while belong together: do and while aren't separate statements in C-like languages, they're bits of a single do-while statement.
I mean, the loop syntax you propose looks pretty equivalent to me - you've just renamed do to repeat and while to exit and moved the exit inside the braces, making it look like a separate statement. I'm not sure if your intent is that exit (foo) is now a control directive? If so, it would be a synonym of if (foo) break. If not, it's a pretty irregular construct, and less familiar-looking to folks from a C/C++/C#/Java background.
Correct. final does absolutely not not not mean in Java! A final variable defined inside a loop takes on a different value for each iteration of the loop.