On Sunday, May 28, 2017 16:49:16 Brad Roberts via Digitalmars-d-learn wrote:
> Is there a mechanism for declaring something pure when it's built from
> parts which individually aren't?
>
> string foo(string s)
> {
>      // do something arbitrarily complex with s that doesn't touch
> globals or change global state except possibly state of the heap or gc
>      return s;
> }

Either everything the function is doing is pure, or it can't be pure without
cheating, and cheating is usually a bad idea. There is no @trusted
equivalent for pure. Now, if you're absolutely sure that the function
doesn't do anything that's actually going to run afoul of pure and what the
compiler will assume about pure functions, but it's using stuff that wasn't
properly marked as pure, or does something that can't be marked as pure for
some reason but in this context would actually be fine, you can cast.

For instance, std.datetime's LocalTime is a singleton which gets the
timezone conversion from the system. Its operations can't be pure, but it
can be constructed as pure, and because it's a singleton, it will return the
same instance every time. Originally, a static constructor was used to
initialize the singleton (which therefore worked great with pure), but
because of circular dependency pain with static constructors, we had to get
rid of the static constructors in std.datetime. The solution was to move the
initialization into another function which was not pure, and then when we
call it from theh singleton function, we cast it to pure:

    static immutable(LocalTime) opCall() @trusted pure nothrow
    {
        alias FuncType = @safe pure nothrow immutable(LocalTime) function();
        return (cast(FuncType)&singleton)();
    }

    static immutable(LocalTime) singleton() @trusted
    {
        import core.stdc.time : tzset;
        import std.concurrency : initOnce;
        static instance = new immutable(LocalTime)();
        static shared bool guard;
        initOnce!guard({tzset(); return true;}());
        return instance;
    }

Now, in the vast majority of cases, I would strongly advise against cheating
in this manner, because you need to be absolutely sure that you're not
actually violating pure (particularly what the compiler will assume about
pure) by what you're doing, and usually what it comes down to is that
something that your function is calling needs to be fixed so that it can be
inferred as pure, or it simply needs to be marked as pure. Casting is a
horrible hack that should only be used as a last resort and only when you're
100% sure that it's fine. However, you _can_ use casting as a backdoor if
you really have to.

- Jonathan M Davis

Reply via email to