Menu

#277 Twine#add/1 violates EList#add/1's contract

open
local elib (53)
3
2005-08-28
2005-08-15
No

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.

Discussion

  • Mark Samuel Miller

    • assigned_to: nobody --> caplet
     
  • Mark Samuel Miller

    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.

     
  • Mark Samuel Miller

    • status: open --> closed-fixed
     
  • Mark Samuel Miller

    • status: closed-fixed --> open-fixed
     
  • Mark Samuel Miller

    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.

     
  • Mark Samuel Miller

    • status: open-fixed --> open
     

Log in to post a comment.

MongoDB Logo MongoDB