writeln if not empty

Jonathan M Davis jmdavisProg at gmx.com
Mon Mar 10 21:14:08 PDT 2014


On Monday, March 10, 2014 21:50:25 Nick Sabalausky wrote:
> On 3/10/2014 9:24 PM, Timothee Cour wrote:
> > Is there a way to do the following lazily:
> > 
> > writelnIfNotEmpty(T)(T a){
> > auto b=text(a);
> > if(b.length)
> > 
> >    writeln(b);
> > 
> > }
> > 
> > ie, without using std.conv.text (which needlessly computes an intermediate
> > string, which could be quite large) or launching a separate process ?
> > 
> > writelnIfNotEmpty(""); //doesn't print new line
> > writelnIfNotEmpty("a"); //prints "a\n"
> 
> Sounds like what you need is a version of to!string() or text() that
> takes an output sink. Taking a look at std.conv, I'm kinda surprised I
> don't see one :/

std.format.formattedWrite will do the equivalent of writef to an output range, 
though I'm not sure that that will really do what the OP wants, since it would 
still have to write the result to an output range even if it were empty, and 
odds are that the output range would be something on the heap anyway (e.g. 
Appender is technically on the stack, but it's contents are on the heap), 
making it so that it probably doesn't help much in this case.

Though to be honest, I'm not quite sure why writelnIfNotEmpty would be very 
useful unless what's being passed in would result in the empty string, and I 
would think that that would almost always be detectable (the one exception 
being user-defined types whose toString results in an empty string). Something 
as simple as

void writelnIfNotEmpty(T)(T a)
{
    static if(isInputRange!T)
    {
        if(!a.empty)
            writeln(a);
    }
    else
        writeln(a);
}

would then cover most cases - the one exception being toStrings which can 
result in empty. And if that's a concern, then something like

    else static if(is(T == struct) || is(T == class))
    {
        auto b = to!string(a);
        if(b.length)
            writeln(b);
    }

should take care of the toString case. It doesn't avoid creating an 
intermediate string, but unless the toString takes an output range, it's 
always going to allocate anyway, and if it does take an output range, once 
again, you'd need one which somehow avoided allocating altogether, which isn't 
particularly likely.

Alternatively, you could just assume that no toString will result in the empty 
string, as it's probably pretty rare that it would, but I'm not sure that that 
would actually save you any overhead except in the case where the toString 
takes an output range (since otherwise, it'll allocate a new string 
regardless), but toStrings which take output ranges are fairly uncommon at 
this point.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list