Should for loops auto cast numbers to strings?

    for (var c in "1")
    for (var c in 1) // throws Can't cast Object type [Number] to a value of type [collection] on line 4

FWIW, the same behavior exists if the number is in a variable. It doesn’t just have to be a constant.

foo = 1
for (var c in foo ) {}

Based on that, I’d be tempted to say yes. Otherwise, you’d potentially get unexpected results if the list you were using only had a single numeric value and Lucee decided to store it as an int behind the scenes.

there’s another casting gotcha with type=“numeric” arguments, a number passed as a string is validated but still isn’t number as it’s passed by reference, which is fun when with serialising to json

IMO an error is appropriate here. Why should Lucee assume that you meant a string? If anything it is more logical to assume an array, i.e. interpret the snippet above as

for (var c in [1]){ }

That doesn’t make any sense. If it were an array literal, it would have square brackets, but it didn’t so it’s not array. As far as Lucee is concerned it is an expression that evaluates to a simple value which IMO should be treated as a single-item list given the context of the code. Lists are the only simple values that can be interpreted as a collection so when you ask Lucee to treat a simple value as a collection, a list is the only reasonable thing to treat it as. The fact that Lucee has chosen to represent this simple variable behind the scenes as something more specific than a java.lang.String is of no consequence. A backend implementation detail that shouldn’t bleed over into CFML.

which produces the same outcome, list behaviour elsewhere handles this conversion

1 Like

If it was up to me then List iterators would have been removed completely. They’re horrible.

I see more sense in iterating over the characters in a string:

for (var c in "Lucee")
  echo(c & "<br>");

will output


at least we don’t have to use hasOwnProperty()!

It can be an inherited property too. You can check with isDefined() or isNull(), e.g.

if (!isNull(arguments.lhs.compareTo)) { ... }

Mixing threads… If you care about performance at all, don’t use List iterators :wink:

Now treating a string as an array of chars isn’t a bad idea. Lucee already courts that when it lets you do

foo = 'test'
foo[ 1 ]

Of course, you can also iterate over the chars in a string by using an empty delimiter, but I assume the for x in y syntax doesn’t allow you to use a non-standard delimiter which sort of screws that up. You’d have to explicitly convert it to an array with foo.listToArray( '' ) but that also wouldn’t work in this scenario due to the long standing bug of string and list member functions not working when the underlying Java object isn’t a string.

listToArray("zac is testing", "")

works nicely image

In CFML (Lucee and ACF) a type definition is only a test (can that value be converted to that type or not?).
Never a conversation to that type. Actually in the beginning Railo did convert the values what caused incompatibility issues with ACF and was reported as a bug.

was it ever considered making passby=“value” return as the specified type?

As you know i see that differently. it is not as simply and clear as you made it.
In CFML a string and a number is not always the same, CFML makes sometimes a distinction between this types, specially when it comes to member function, it is important because string member functions can conflict with member functions from other simple types.
But in that case i agree, i see no possible conflicts or performance issues supporting this.
So +1 from me


@micstriit Can you elaborate on that? I’m not aware of any that overlap. There’s only really 3 simple types: string, date, and list. Date has zero overlap from what I can tell and all the list member functions start with the word “list” so no overlap there either.