Monday 31 December 2012

Lists with empty-string delimiters

G'day:
Blimey; three articles today. Once again, this stems from a thread on the Railo Google Group, this time regarding a bug I found in Railo (or that I think is a bug), which resulted in some questioning whether it's a bug in Railo, a bug in ColdFusion, or a bug in both. And the more I look into it, the less sure I am about it.

And the situation I found the... erm... "anomalous  behaviour" (shall I say) was in the code I was writing for the previous two articles' investigation.


The "bug" I found is demonstrated here:

string = "ABCDEFGHIJ";
charArray = listToArray(string, ""); // note that is an empty string
writeDump(variables);

On ColdFusion I get what I was wanting:

struct
CHARARRAY
array
1A
2B
3C
4D
5E
6F
7G
8H
9I
10J
STRINGABCDEFGHIJ

On Railo I get this:

Scope
CHARARRAY
Array
1
stringABCDEFGHIJ
STRING
stringABCDEFGHIJ

Which is neither use nor ornament, I think we can agree at least on that.

Still, a valid question was raised: should ColdFusion be doing this? There was a bit of defensiveness from the Railo community peeps in that I suggested there was perhaps an incompatibility bug here (in is definitely an incompatibility, as the behaviour is different), but a coupla sensible comments to the effect that perhaps an empty string should not be a valid delimiter. Fair point (and something I did mention from the outset). All that means is that ColdFusion has got a bug too, it does not mitigate the fact that Railo still has one: if an empty string is not valid, then it should be rejected (ie: with an error).

Anyway, that's being dealt with on the thread if you want to read about that. It's dry stuff, and content-lite.

What I have investigated now is I've tried to work out whether an empty string ought to work as a delimiter, or whether it ought not. And what the behaviour should be. I have done this by testing various other list operations with empty-string-delimiters, and tried to infer what the over-all intent was. The code I used to get the results is as follows:


Basically I ran though each of the list functions and checked what they did with an empty-string delimiter. I've run this on both CF10 and Railo 4.0.2, and this is the combination of both:

OperationResultSame?Observation
CF10Railo 4.0.2
listAppend()12345678901234567890YESBoth are wrong: the operation has not actually worked
listChangeDelims()12345678901234567890YESDelimiter ignored
listContains()11YESDelimiter ignored
listDeleteAt()Invalid list index 5. In function ListDeleteAt(list, index [, delimiters]), the value of index, 5, is not a valid as the first argument (this list has 1 elements). Valid indexes are in the range 1 through the number of elements in the list.invalid call of the function ListDeleteAt, second Argument (index) is invalid, index must be a integer between 1 and 0YESRailo's error message has a glitch in it ("between 1 and 0")
listFind()00YESDelimiter ignored
listFirst()12345678901234567890YESDelimiter ignored
listGetAt()Invalid list index 5. In function ListGetAt(list, index [, delimiters]), the value of index, 5, is not a valid as the first argument (this list has 1 elements). Valid indexes are in the range 1 through the number of elements in the list.invalid call of the function listGetAt, second Argument (posNumber) is invalid, invalid string list index [5]YESDelimiter ignored
listInsertAt()Invalid list index 5. In function ListInsertAt(list, index [, delimiters]), the value of index, 5, is not a valid as the first argument (this list has 1 elements). Valid indexes are in the range 1 through the number of elements in the list.invalid string list index [5], indexes go from 1 to 1YESDelimiter ignored
listLast()12345678901234567890YESDelimiter ignored
listLen()11YESDelimiter ignored
listQualify()String index out of range: 1'1234567890'NOBug in CF
listRest()YESDelimiter ignored
listSetAt()Invalid list index 5. In function ListSetAt(list, index [, delimiters]), the value of index, 5, is not a valid as the first argument (this list has 1 elements). Valid indexes are in the range 1 through the number of elements in the list.invalid call of the function listSetAt, second Argument (position) is invalid, invalid string list index [5], indexes go from 1 to 1YESDelimiter ignored
listSort()12345678901234567890YESDelimiter ignored
listToArray()array [1,2,3,4,5,6,7,8,9,0]array ["1234567890"]NOCF respects the delimiter, Railo does not
listValueCount()00YESDelimiter ignored
valueList()wherokarakakakarikiwherokarakakakarikiYESBoth respect the delimiter

On the whole, both simply ignore the empty-string delimiter. Which I think is wrong. It should either be respected and work, or it should error.

There are a coupla "interesting" cases that I have highlighted:
  1. not only has listAppend() not respected the empty-string delimiter, it simply hasn't done anything at all. This is a bug in both CF and Railo, surely?
  2. Railo has a slight wording glitch in its error message for listDeleteAt().
  3. ColdFusion has a bug in listQualify().
  4. listToArray() is the case where I initially reported the divergent behaviour. One or both of CF & Railo have a bug here (Railo definitely does; CF might do).
  5. Curiously, both engines support an empty-string delimiter for valueList().
(I've just highlighted "wherokarakakakariki" to demonstrate where each list element is).

Based on most functions not supporting an empty-string delimiter, I think it's anomalous that a couple of the functions do. I think they should all raise exceptions. Or... they should all respect the empty-string delimiter and work properly. Which is not the case for almost all of these functions.

That said, this is all pretty trivial sh!t, and if both platforms simply did the same thing in all cases, that'd be cool. However I think the behaviour of listAppend() on both is wrong whichever way one spins it; CF has a bug to think about with listQualify(); and Railo has a wee bug with that error message, plus probably ought to change its behaviour of listToArray().

Thoughts?

--
Adam