@api: One attribute to rule them All

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


On Tuesday, 6 January 2015 at 09:12:43 UTC, John Colvin wrote:
> 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).

tldr: I like what you're thinking, please can we have this.


More information about the Digitalmars-d mailing list