Mitigating the attribute proliferation - attribute inference for functions

Martin Nowak via Digitalmars-d digitalmars-d at puremagic.com
Sat Apr 11 14:46:57 PDT 2015


Sorry to open yet another topic.

I'm repeatedly finding myself in situations where I write functions like
this.

    private @property bool empty() const @safe pure nothrow @nogc
    {
        return impl is null || !impl.count;
    }

This is obviously a joke, because the compiler very well knows the
attributes and I don't need to guarantee them as part of an API.
The situation is getting somewhat out of hands and we need to find a way
to make attribute inference for functions feasible.

At the last D Meetup [¹] I had a nice chat with Dicebot about this.
We both had the same notion of how things should be. People should put
attributes on their exported API functions (or main() for apps), thereby
making API guarantees and transitively enforcing them, but the compiler
should infer attributes for internal functions.

This wouldn't help with separate compilation of modules, because the
compiler only knows the attributes of a function after semantically
analyzing it, but it works extremely well for libraries that are
compiled as batch.
And given that separate compilation is inherently inefficient anyhow,
it's well worth to look at this approach in more detail.

The main problem of attribute inference for functions presents as
follows on API borders.

/// An API function that guarantees certain attributes
public size_t foo(string a) @safe @nogc pure nothrow
{
    // and calls an internal function
    return impl(a);
}

/// An API template function with the same guarantees
public size_t bar(R)(R a) @safe @nogc pure nothrow
{
    // that calls an internal function
    return impl("something");
}

/// A function with inferred attributes
private size_t impl(string a)
{
    return a.length;
}

Applying attribute inference to `impl` would work for `foo` because code
calling `foo` doesn't need to check the attributes of `impl`, except
when foo gets inlined.
This doesn't work for the template function bar, because attributes are
checked when the template is instantiated, leaving us with the following
options on how the compiler could deal with missing attributes of a
function.

1) If that function has source code available, it gets semantically
analyzed and additional attributes are inferred.

2) The compiler errors because of missing attributes.

3) Don't inline functions when that would require to infer attributes of
a private/package function.

4) ???

Option 1 isn't really viable because it turns into a whole program
compilation model.

Option 2 is basically what we have today. Without a clear border of
where the compiler stops to analyze your implementation details, it'd
still be necessary to annotate every function.

Option 3 defines such a border which allows to use attribute inference
for internal functions. In the above example `bar` wouldn't work without
inference on `impl`, but it's possible to manually annotate the private
functions directly used by a template.

Those ideas aren't thought through too well, but it's an important issue
that requires a solution.

-Martin

[¹]: http://www.meetup.com/Berlin-D-Programmers/events/220702368/


More information about the Digitalmars-d mailing list