write, toString, formatValue & range interface

Robert Jacques sandford at jhu.edu
Tue Dec 14 06:35:20 PST 2010


On Tue, 14 Dec 2010 05:02:41 -0500, spir <denis.spir at gmail.com> wrote:
> 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
>

Having recently run into this without knowing it, vote++. Also, please  
file a bug report (or two).


More information about the Digitalmars-d mailing list