write, toString, formatValue & range interface

spir denis.spir at gmail.com
Tue Dec 14 02:02:41 PST 2010


Hello,


Had a nice time degugging an issue after having added an input range interface to a (big) struct type. Finally managed to deduce the problem happens when writing out an element of the struct type. This introduced an infinite loop ending in segfault. Found it weird because the struct's toString does not iterate over the type, so there was no reason to use the range interface.
This is why I guessed toString was not called. And in fact, forcing its use by explicitely calling .toString() solved the bug! 2 correspondants (Stephan Mueller & Ivan Melnychuk) helped me by pointing to the various template-selection criteria of formatValue.



There seems to be a pair of bugs in the set of formatValue templates constaints, which cause the following problems:
* If a class defines both toString and a range interface, compiler error (additional bug pointed by Stephan Mueller).
* For structs, the presence of a range interface shortcuts toString.
* If a range outputs elements of the same type, writing (and probably other features) runs into an infinite loop. This case is unchecked yet.



The following changes may, I guess, solve the first two problems:
(1) structs added (with classes) to the template selecting the use of toString
(2) the template that selects the use of ranges checks there is no toString
(3) the special case of using t.stringof for stucts must be selected only in last resort -- actually, this case may be suppressed and integrated into the general class/struct case.

This means changing the following formatValue templates (quickly written, absolutely untested ;-):

// case use toString (or struct .stringof): add structs
void formatValue(Writer, T, Char)(Writer w, T val, ref FormatSpec!Char f)
if (is(T == class) || is(T == struct))
{
    // in case of struct, detect whether toString is defined, else use T.stringof
}

// case use range interface: check no toString available
// also add a test that the range does not output elements of the same type!!!
void formatValue(Writer, T, Char)(Writer w, T val,
        ref FormatSpec!Char f)
if (
    isInputRange!T && !isSomeChar!(ElementType!T) ||
    ! is(typeof(val.toString() == string))
)
{...}

// special case use T.stringof for struct: useless? (else check no toString)
void formatValue(Writer, T, Char)(Writer w, T val,
        ref FormatSpec!Char f)
if (
    is(T == struct) && !isInputRange!T &&
    ! is(typeof(val.toString() == string))
)
{
    put(w, T.stringof);
}



Also, (1) the online doc of std.format seems outdated, no constraint for instance (2) the in-source doc is rather confusing, several comments do not describe the following code.



Hope this helps,
Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



More information about the Digitalmars-d mailing list