eclipse-archived/ceylon

for-loop over byte ranges gives type error on try.ceylon-lang.org

ePaul opened this issue · 3 comments

ePaul commented

Wrong behavior
Try to iterate over a range of bytes with a for-loop:

for (b in 0.byte..3.byte) {
    print(b);
}

Try it!
Trying to run this on try.ceylon-lang.org gives this error:

	undefined	 — 	Runtime error:
	undefined	 — 	--- TypeError: $1i.compare is not a function
Script ended with no output

Expected behavior
Running this code should print

0
1
2
3

Analysis
From the error message, it looks like some part of the compiler is trying to convert this into a classic increment-comparison loop. But bytes in Ceylon have no total ordering, and thus also no comparison operators or compare functions.

xkr47 commented

Should the .. operator complain about the type not having total ordering? Or how should it work?

The .. operator is syntax sugar for ceylon.language::span, which only requires that its arguments be of a type satisfying Enumerable, and (per its docs)

An Enumerable type is characterized by each element having well-defined offset and neighbour() functions.

Bytes don't have a total ordering in Ceylon because they aren't specifically signed or unsigned, and offset and neighbour are defined in terms of modular arithmetic, wrapping around.

I tried the code in the OP above on the JVM, and it gives the results shown under "Expected behavior" above. I also compiled it to JS using ceylon compile-js, and the code above compiled to

var $3=(0).$_byte,$2=(3).$_byte,$4=$3.compare($2),$5=$4===m$1.smaller()?'successor':'predecessor';for(var $6=m$1.eorl$($4);$6($2,$3);$3=$3[$5]){
m$1.print($3);
}
ePaul commented

Ah, so the problem is not on the loop condition, but already when trying to figure out whether to do an upwards or downwards iteration, which doesn't apply for a recursive Enumerable type like Byte. I guess that first comparison should call $3.offset($2) < 0?