From
http://www.eros-os.org/pipermail/e-lang/2005-August/010971.html
... it's an upsetting bug for reasons that have nothing
to do with these particular changes.
In 0.8.36a and 0.8.36b, updoc was broken because the
new __SplitList guard, now used to expand cdr-patterns
(like '[a, b] + rest'), had the following line:
return list(0,cut) + [list(cut,llen)]
In 0.8.36c the mysterious problem is fixed by changing
this line to:
return list(0,cut).with(list(cut,llen))
Can't see the difference? It's distressingly
non-obvious. Consider:
? def list := "hello"
# value: "hello"
? def cut := 2
# value: 2
? def llen := 5
# value: 5
? list(0,cut) + [list(cut,llen)]
# value: "he[\"llo\"]"
? list(0,cut).with(list(cut,llen))
# value: ['h', 'e', "llo"]
The problem is that E strings, taking after Java
strings, are clever about '+' -- if the argument isn't
a string, as in Java, its printed form is appended
instead. But since an E string is a kind of E list
(Twine is a subtype of EList), this conversion behavior
violates the meaning of '+' inherited from the EList
contract.
I think it's too late to do anything about this hazard
other than document it. Sigh.
Logged In: YES
user_id=54168
From
http://www.eros-os.org/pipermail/e-lang/2005-August/010975.html
Ka-Ping Yee wrote:
> Why not just get rid of this dangerous auto-conversion
behaviour?
> Let "+" be defined for operands of consistent types and use
> quasiliterals for formatting. I don't think
auto-converting addition
> should ever have been part of the behaviour of strings in
the first
> place, and seem to recall a discussion about this issue
some time ago.
I'm trying out an interesting compromise represented by the
following changed
beginning of the Twine#add/1 method. The middle else-if case
and the comments
are new:
public ConstList add(Object other) {
Twine otherTwine;
if (other instanceof Twine) {
otherTwine = (Twine)other;
} else if (other instanceof EList) {
// Must honor the EList contract when it would
succeed
ConstList result = super.add(other);
# ... traces E stack & result
return result;
} else {
// Convert only when super.add/1 would fail.
otherTwine = Twine.fromString(E.toString(other));
}
# ... as before
As it says, this honors the EList#add/1 contract in cases
where it would
succeed, and only does the weird Java-like string coercion
when EList#add/1
would otherwise have failed. Since we can't statically
detect which programs
this would break, I trace occurrences of the problematic
cases. It immediately
caught several, of which the following is typical:
In dragDropKit.emaker:
def flavors := [DataFlavor(mimeType)]
traceline("transfer flavors: " + flavors)
The above code, by honoring the EList#add/1 contract,
creates and traces a
list whose initial elements are characters and whose final
element is a
DataFlavor. This has been fixed to
traceline(`transfer flavors: $flavors`)
which more clearly expresses the original intent anyway.
Interestingly, all the cases caught so far have been in
diagnostics. None
effected the correctness of the program's normal
functioning. We'll see if our
luck continues.
Logged In: YES
user_id=54168
I am reopening this bug. The current system warns on x + y
if x is a Twine and y is not. If y is a non-Twine list, then
the result is correctly a list concatenating these elements,
but we warn for now as this is a change in behavior that
probably represents a bug in an old program. If y is a
non-list, then we still stringify for now, but this behavior
is no longer considered correct. In an upcoming release,
we'll retire such stringification and close this bug.