dpurely-functionalnothrowmemory-safety

Preferred Way of Building Strings in D


What is the preferred way of constructing strings with regards to the function attributes @safe, pure and nothrow and compile-time and run-time performance of the parenting function?

Should we either use, for instance

format("Variable x=%s should equal %s", x, x_)

or

"Variable x=" ~to!string(x)~ " should equal " ~to!string(x_)

I reckon the format version is easier on the eye but is it better in other regards?

There could be a slight performance hit on compilation time because the format strings and its arguments has to be CTFEed right?


Solution

  • The first version is generally better. There's no significant difference in compiliation performance (if any, forrmat isn't ctfe), and format() should actually perform better.

    The binary "foo" ~ "bar" is often surprisingly expensive because it allocates intermediate results that the garbage collector then has to clean up.

    On the dmd version I have, neither version actually compiles as safe, nothrow, pure. I think they fixed this in phobos git, but I'm not sure. Regardless, right now neither actually works, and there's no easy workaround aside from implementing your own function, unless it is just for debugging.

    The pure requirement is relaxed in debug statements, and you can wrap non-@safe functions in @system, and throwing functions in try/catch to get those attributes in.

    Thus, this would actually compile:

    // trusted gets around safe
    @trusted pure nothrow string myformat(T...)(in string fmt, in T t) {
    import std.string;
        // debug gets around the pure requirement
    debug try // try gets around nothrow
        return format(fmt, t);
    catch(Exception e) { }
    
    return null;
    }
    
    @safe nothrow pure void main() {
    import std.conv;
    string s = myformat("test %s", 10);
        assert(0, s); // the assert message shows up
    }
    

    compile with the -debug switch: dmd test.d -debug

    So not a great solution, but until the phobos functions with the proper attributes are released, or if you want to write your own format() or to() functions (not really that hard, you can do int to string in < 10 lines) probably the best you can do.