Blog post: What D got wrong

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Dec 18 11:25:17 UTC 2018


On Tuesday, December 18, 2018 3:36:15 AM MST Pjotr Prins via Digitalmars-d-
announce wrote:
> On Thursday, 13 December 2018 at 18:29:39 UTC, Adam D. Ruppe
>
> wrote:
> > On Thursday, 13 December 2018 at 10:29:10 UTC, RazvanN wrote:
> >> Do you honestly think that they will ever take D into account
> >> if @safe and immutable data will be the default?
> >
> > D needs to stop chasing after what you think people think they
> > want and just start being good for us.
> >
> > The majority of my code is written pretty permissively - I like
> > my pointers, my gotos, my GC, my exceptions. But I'm willing to
> > consider the change because I actually don't think it will be
> > that big of a hassle, and will be better overall. I wanna show
> > you something:
> >
> > /// Static convenience functions for common color names
> > nothrow pure @nogc @safe
> > static Color transparent() { return Color(0, 0, 0, 0); }
> >
> >
> > The attribute spam is almost longer than the function itself.
>
> Isn't it the way forward that the compiler deduces these
> attributes and fills them in automatically? All these can be
> inferenced. Only when the caller wants to guarantee, say pure, it
> could add it explicitly. I read somewhere that the compiler
> already does this to some degree. And even the generated docs
> should be able to show it.

In general, functions that have to have their source available have their
attributes inferred. So, templated functions, lambdas, and auto return
functions all have attribute inference at this point. Attribute inference
was introduced originally as being only for templated functions, because you
_have_ to have it for them for them to really work with attributes (at least
in any situation where whether an attribute is applicable depends on the
template arguments - which is frequently the case), but it's been expanded
over time. However, D's compilation model is such that many functions will
never have attribute inference, because it's frequently not guaranteed that
the compiler has the source code for a function in all cases where it's
called.

That being said, there are some serious downsides to attribute inference. It
makes it much harder to know which attributes actually apply to a function,
and it tends to result in folks not bothering with making sure that they're
code works with a particular attribute; they just let attribute inference
take care of it all and don't worry about it (in which case, the result is
comparable to not having attribute inference in some respects). Another big
issue is that when the attributes are inferred, it, becomes _very_ easy to
accidentally change which attributes a function has when changing its
implementation (similar to how its very easy to accidentally make it so that
a function no longer works with CTFE). The primary way to combat that is to
use explicit attributes on the unittest blocks which test the function, but
that's easy to forget to do, and in a way, it's just moving the explicit
attributes from the function itself to the unit tests. So, whether it
actually fixes anything is debatable.

In general, the cleanest approach is to be as explicit about attributes as
possible (which means still using attribute inference with templated
functions when the attribute should depend on the template arguments but to
not use it much of anywhere else). However, that then requires that you mark
up your functions everywhere, which can be very tedious, and many folks
don't want to do it. Of course, using more attribute inference reduces that
particular problem (which is why many folks want it), but you then get a
different set of problems due to the fact that attributes are inferred
instead of explicit.

So, there's really no winning. In some ways, minimizing attribute inference
is the best option, and in others, maximizing it would be better. Probably
the best solution to the problem would be to have the defaults better match
up with what your average program needs, but no set of defaults fits every
program, and different coding styles can result in very different opinions
on which set of attributes should be the default. I very much doubt that you
would find much of a consensus on it even just within the core set of
developers working on dmd, druntime, and Phobos.

My guess is that if code breakage were somehow not part of the question that
the majority of D programmers would be in favor of @safe by default, since
the vast majority of code can be @safe (though plenty of the time
programmers don't bother to mark it as @safe), and in theory, only small
portions of a program should typically need to be marked as @system. But I
expect that any other attribute would result in a lot of arguing. For
instance, in some respects, pure would be great as the default, but that
doesn't interact well at all with stuff like I/O, making it so that you have
to write your programs in a certain way for pure to work well for most
functions, and not everyone wants to do that. Some folks might want nothrow
to be the default, because they don't use exceptions much, but it would be a
disaster in code that did use exceptions much. And having const or immutable
as the default would be highly controversial. Some folks really want it, but
a lot of code simply wouldn't work well that way (including ranges as things
currently stand), meaning that a _lot_ of code would have to be marked with
mutable (or whatever the attribute would be to undo the default of const or
immutable). Some folks might want nothrow to be the default, because they
don't use exceptions much, but it would be a disaster in code that did use
exceptions much. So, any pretty much any change to the defaults for
attributes would likely result in a _lot_ of arguing.

The biggest thing that we clearly can do and have talked about from time to
time but have never actually done is to introduce a way to reverse
attributes that currently can't be reversed - e.g. having something like
pure(false). That way, it would become easier to just mark entire modules
with an attribute by doing something like @safe: at the top. Of course, that
would still leave the problem of either not being able to have templated
code in that module or needing a way to indicate that an attribute should be
inferred for a function instead of using the explicit attribute that's being
used on the entire module. So, a DIP on the subject would probably need to
worry about fixing that problem, but regardless of the fine details, we
really should get a DIP for that at some point here. And it's well-written,
with a solid approach to the problem, I fully expect that it would be
accepted. It's just that no one has cared enough to write such a DIP.

Of course, even if we _did_ have a solution for reversing attributes,
slapping an attribute on the top of the module would still potentially be a
maintenance problem, because it's then really easy to miss that an attribute
is in effect (it's a problem that we've had on several occasions with
druntime and Phobos in the few cases where attributes are mass-applied). So,
there is no silver bullet here (though regardless of whether mass-applying
attributes is something that should ever be considered good practice, we
really should add a way to be able to reverse them).

- Jonathan M Davis





More information about the Digitalmars-d-announce mailing list