Help

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.

12 comments:
 
18. Jul 2011, 07:14 CET | Link
jlaz

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.

ReplyQuote
 
18. Jul 2011, 10:58 CET | Link
Quintesse

@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.

 
18. Jul 2011, 11:16 CET | Link
jlaz wrote on Jul 18, 2011 01:14:
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.

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?

 
18. Jul 2011, 12:38 CET | Link

Ah, now I think I understand what you're trying to say. I think that when you wrote declared, you meant to write definitely assigned. 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.)

 
18. Jul 2011, 13:12 CET | Link

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 < size

So that all loops start with loop, there is an optional loop variable, and you can break for a loop using while and until. Something like this.

 
18. Jul 2011, 15:37 CET | Link
Wouter Oet

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.

 
18. Jul 2011, 15:53 CET | Link
Stef Epardaud
There already is support for that: http://in.relation.to/Bloggers/IntroductionToCeylonPart4#H-IteratingSequences
 
18. Jul 2011, 19:41 CET | Link
David

Did you say that you would like a loop condition to depend on the value of a final variable??

 
18. Jul 2011, 20:07 CET | Link

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 scope 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);
}
 
18. Jul 2011, 20:12 CET | Link
> IteratingSequences

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.
 
18. Jul 2011, 23:30 CET | Link
What throws me off is that the while condition is evaluating a value that is defined within a scope that the while condition is not in.

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.

Since you are writing the definition of a language, why include a do.. while ? Why not do something completely different like

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.

 
18. Jul 2011, 23:33 CET | Link
David wrote on Jul 18, 2011 13:41:
Did you say that you would like a loop condition to depend on the value of a final variable??

Correct. final does absolutely not not not mean global constant in Java! A final variable defined inside a loop takes on a different value for each iteration of the loop.

Post Comment