On 29.07.19 21:35, H. S. Teoh wrote:
Generally, the idiom is to let the compiler do attribute inference by
templatizing your code and not writing any explicit attributes, then use
unittests to ensure that instantiations of the range that ought to have
certain attributes actually have those attributes.  For example, instead
of writing:

        struct MyRange(R) {
                ...
                @property bool empty() const { ... }
                ...
        }

write instead:

        struct MyRange(R) {
                ...
                // No attributes: compiler does inference
                @property bool empty() { ... }
                ...
        }

        // unittest ensures .empty is callable with const object.
        unittest {
                const rr = MyRange!(const(Range))(...);
                assert(rr.empty); // will fail compilation if .empty is 
non-const
        }

The unittest tests that a specific instantiation of MyRange has const
.empty. It's still possible to use MyRange with a range that has
non-const .empty, but this unittest ensures that the non-const-ness
wasn't introduced by the implementation of MyRange itself, but only
comes from the template argument.

But const isn't inferred.

----
struct MyRange()
{
    @property bool empty() { return true; }
}
void main()
{
    pragma(msg, typeof(&MyRange!().empty));
        /* Prints: "bool function() pure nothrow @nogc @property @safe"
        Note: no const. */
    const MyRange!() r;
    assert(r.empty); /* fails compilation */
}
----

Reply via email to