leaky abstraction

A leaky abstraction is an implementation of a concept (the abstraction) which is flawed in that it allows details of the implementation to shine through.

See also http://en.wikipedia.org/wiki/Leaky_abstraction


One area where Tcl has been plagued by a leaky abstraction is that numeric Tcl_Objs have failed to fully realise the everything is a string principle. This has been the case for most of Tcl 8.x, but is fixed as of 8.5.

Historical details:

The most long-standing bug in this area was that for floating-point numbers. Basically the problem was that the numbers were stored with full precision as a double in the Tcl_Obj, but only tcl_precision digits were preserved in the string representation, which could lead to apparent contradictions such as:

 % info patchlevel
 8.4.7
 % set tcl_precision
 12
 % set third [expr {1.0/3}]
 0.333333333333
 % expr {$third*3}
 1.0
 % expr $third*3
 0.999999999999

In the braced expr, Tcl uses the internal representation of $third, which is close enough to 1.0/3 that it gets rounded to 1.0 when multiplied by 3. In the unbraced expr, there is only the string representation 0.333333333333 to work with, and 3*0.333333333333 = 0.999999999999, as claimed. (Incidentally, it was this kind of small discrepancies between internal and string representations of numbers that led to the discovery of the Lorentz attractor [L1 ] and deterministic chaos.) Tcl 8.5 keeps more digits and gets it right either way:

 % info patchlevel
 8.5.0
 % set tcl_precision
 0
 % set third [expr {1.0/3}]
 0.3333333333333333
 % expr {$third*3}
 1.0
 % expr $third*3
 1.0

But for backwards compatibility, the faulty behaviour can be restored:

 % set tcl_precision 12
 12
 % set another_third [expr {1.0/3}]
 0.333333333333
 % expr {$another_third*3}
 1.0
 % expr $another_third*3
 0.999999999999

Note also that we still have

 % expr $third*3
 1.0

since that string representation was generated before tcl_precision was changed.

In Tcl 7, there were no Tcl_Objs, so EIAS was implementation truth rather than an abstraction. tcl_precision did the same now as then, but it had no effect on the EIAS principle; rather it modified how expr rounded numbers.

In Tcl 8.4, the introduction of wide gave birth to another leak in EIAS:

 % info patchlevel
 8.4.7
 % set tcl_platform(wordSize)
 4
 % set i 70000
 70000
 % set w [expr wide($i)]
 70000
 % string equal $i $w
 1
 % proc square {a} {expr {$a*$a}}
 % square $i
 605032704
 % square $w
 4900000000

Since this generally shows up as large differences, whereas the float bug shows up as small differences, it is a much more severe bug. However, it too was fixed in Tcl 8.5:

 % info patchlevel
 8.5.0
 % set i 5000000000
 5000000000
 % set w [expr wide($i)]
 5000000000
 % string equal $i $w
 1
 % proc square {a} {expr {$a*$a}}
 % square $i
 25000000000000000000
 % square $w
 25000000000000000000
 % expr wide([square $w])
 6553255926290448384