@api: One attribute to rule them All

John Colvin via Digitalmars-d digitalmars-d at puremagic.com
Tue Jan 6 01:12:42 PST 2015


On Monday, 5 January 2015 at 21:15:00 UTC, Zach the Mystic wrote:
> Hello everybody. My name is Zach, and I have a suggestion for 
> the improvement of D. I've been looking at the following 
> stalled pull request for a while now:
>
> https://github.com/D-Programming-Language/dmd/pull/1877
>
> ...in which Walter Bright wants to introduce built-in-attribute 
> inference for a relatively small set of functions. It seems 
> like the most obvious thing in the world to me to desire this, 
> and not even just for 'auto' and templated functions, but for 
> *every* function. And there's no reason it can't be done. So 
> long as the compiler has everything it needs to determine which 
> attributes can be applied, there's no reason to demand anything 
> from the programmer. Look how simple this function is:
>
> int plusOne(int a) { return a+1; }
>
> Let's say I later want to call it, however, from a fully 
> attributed function:
>
> int plusTwo(int a) pure nothrow @safe @nogc  {
>   return plusOne(plusOne(a));
> }
>
> I get a compiler error. The only way to stop it is to add 
> unnecessary visual noise to the first function. All of these 
> attributes should be something that you *want* to add, not 
> something that you *need*. The compiler can obviously figure 
> out if the function throws or not. Just keep an additional 
> internal flag for each of the attributes. When any attribute is 
> violated, flip the bit and boom, you have your implicit 
> function signature.
>
> I think this is how it always should have been. It's important 
> to remember that the above attributes have the 'covariant' 
> property, which means they can always be called by any function 
> without that property. Therefore no existing code will start 
> failing to compile. Only certain things which would have 
> *errored* before will stop. Plus new optimizations can be done.
>
> So what's the problem? As you can read in the vehement 
> opposition to pull 1877 above, the big fear is that function 
> signatures will start changing willy-nilly, causing the exposed 
> interface of the function to destabilize, which will cause 
> linker errors or require code intended to be kept separate in 
> large projects to be recompiled at every little change.
>
> I find this depressing! That something so good should be ruined 
> by something so remote as the need for separate compilation in 
> very large projects? I mean, most projects aren't even very 
> large. Also, because D compiles so much faster than its 
> predecessors, is it even such a big deal to have to recompile 
> everything?
>
> But let's admit the point may be valid. Yes, under attribute 
> inference, the function signatures in the exposed API will 
> indeed find themselves changing every time one so much as adds 
> a 'printf' or calls something that throws.
>
> But they don't *have* to change. The compiler doesn't need to 
> include the inferred attributes when it generates the mangled 
> name and the .di signature, only the explicit ones. From within 
> the program, all the opportunities for inference and 
> optimization could be left intact, while outside programs 
> accessing the code in precompiled form could only access the 
> functions as explicitly indicated.
>
> This makes no change to the language, except that it allows new 
> things to compile. The only hitch is this: What if you want the 
> full advantages of optimization and inference from across 
> compilation boundaries? You'd have to add each of the covariant 
> function attributes manually to every function you exposed. 
> From my perspective, this is still a chore.
>
> I suggest a new attribute, @api, which does nothing more than 
> to tell the compiler to generate the function signature and 
> mangle the name only with its explicit attributes, and not with 
> its inferred ones. Inside the program, there's no reason the 
> compiler can't continue to use inference, but with @api, the 
> exposed interface will be stabilized, should the programmer 
> want that. Simple.
>
> I anticipate a couple of objections to my proposal:
>
> The first is that we would now demand that the programmer 
> decide whether he wants his exposed functions stabilized or 
> not. For a large library used by different people, this choice 
> might pose some difficulty. But it's not that bad. You just 
> choose: do you want to improve compilation times and/or 
> closed-source consistency by ensuring a stable interface, or do 
> you want to speed up runtime performance without having to 
> clutter your code? Most projects would choose the latter. @api 
> is made available for the those who don't. The opposition to 
> attribute inference put forth in pull 1877 is thereby appeased.
>
> A second objection to this proposal: Another attribute? Really? 
> Well, yeah.
>
> But it's not a problem, I say, for these reasons:
>
> 1. This one little attribute allows you to excise gajillions of 
> unnecessary little attributes which are currently forced on the 
> programmer by the lack of inference, simply by appeasing the 
> opponents of inference and allowing it to be implemented.
>
> 2. It seems like most people will be okay just recompiling 
> projects instead of preferring to stabilize their apis. Thus, 
> @api will only be used rarely.
>
> 3. @api forces you to add all the attributes you want exposed 
> to the world manually. It's a candid admission that you are 
> okay littering your code with attributes, thereby lessening the 
> pain at having to add one more.
>
> 4. Most @api functions will come in clusters. After all, it 
> *is* an API you are exposing, so I think it's highly likely 
> that a single "@api:" will work in most cases.
>
>
> Now, "Bombard with your gunships."
>
> Thank you.

Needing a function to have a completely stable signature is the 
(very important) exception, not the rule and inference is awesome 
for everywhere else.

It's worth noting that with full inference then much less code 
would be explicitly annotated, which goes some way towards 
ameliorating the stability problem as more client code will be 
flexible w.r.t. changing attributes on library boundaries.

About restriction to `auto`:
`auto` is about return types, not attributes. Inference should be 
performed on anything that's available. *.di files should contain 
the inferred attributes when generated to support totally 
separate compilation. For more convoluted examples, tooling could 
help (compiler spits out json with inference results, external 
tool / IDE picks up that info and helps the user automatically 
apply it to declarations elsewhere).


More information about the Digitalmars-d mailing list