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

Reply via email to