On Monday, 5 January 2015 at 23:48:17 UTC, Joseph Rushton
Wakeling via Digitalmars-d wrote:
Here's the rationale. Suppose that I have a bunch of functions
that are all intended to be part of the public API of my
project. I accidentally forget to tag one of them with the
@api attribute,
A more likely scenario is that your library starts small enough
not to need the @api attribute, then at some point it gets
really, really huge. Then in one fell swoop you decide to "@api:"
your whole file so that the public interface won't change so
often. I'm picking the most extreme case I can think of, in order
to argue the point from a different perspective.
so its attributes will be auto-inferred, but the function is
still public, so downstream users will wind up using it.
3 months later, I realize my mistake, and add the @api
attribute -- at which point downstream users' code will break
if their code was relying on the unintended inferred attributes.
Attribute inference provides convenience, not guarantees. If a
user was relying on the purity of a function which was never
marked 'pure', it's only convenience which allows him to do it,
both on the part of the user, for adding 'pure', and the library
writer, for *not* adding it. Adding @api (or 'extern (noinfer)')
cancels that convenience for the sake of modularity. It's a
tradeoff. The problem itself is solved either by the library
writer marking the function 'pure', or the user removing 'pure'
from his own function. Without @api, the problem only arises when
the library writer actually does something impure, which makes
perfect sense. It's @api (and D's existing default, by the way)
which adds the artificiality to the process, not my suggested
default.
It's quite analogous in this respect to the argument about
final vs. virtual by default for class methods.
I don't think so, because of so-called covariance. Final and
virtual each have their own advantages and disadvantages, whereas
inferring attributes only goes one way. There is no cost to
inferring in the general case. My suggestion, (I now prefer
'extern(noinfer)'), does absolutely nothing except to restore D's
existing default, for what I think are the rare cases it is
needed. I could be wrong about just how rare using
extern(noinfer) will actually be, but consider that phobos, for
example, just doesn't need it, because it's too small a library
to cause trouble if all of a sudden one of its non-templated
functions becomes impure. A quick recompile, a new interface
file, and now everyone's using the new thing. Even today, it's
not even marked up with attributes completely, thus indicating
that you never even *could* have used it for all it's worth.
Have I convinced you?