"default" keyword as function attribute
We often repeat advice to put `@safe:`, or some other function attribute, at the top of your modules to apply the attribute en masse. In practice this quickly becomes infeasible. Sooner or later, a generic function is introduced to idiomatic D modules, and many of them, perhaps most of them, are more general when attribute inference is used. Any explicit attribute application disables inference of that attribute. In my experience this is by far the most common reason that blanket application of attributes is impractical. A recent example is this Phobos PR[1] which cannot apply `@safe` module-wide because the module contains generic functions where attribute inference is desirable. In this particular case it could be avoided by defining those generic functions before declaring `@safe:`, but this is at best unintuitive organization of code, and at worst highly intrusive when the generic function is a member function as it affects the whole type. It would also affect generated documentation with the current state of our tools. DIP 79[2] suggests a number of possible language amendments that would help with this problem. The @attribute(expression>) syntax has support from (and was originally proposed by?) Andrei, but it doesn't really help with the attribute inference problem so I think we should consider it a separate issue. It suggests "default" as a possible function attribute which negates previously applied attributes, which seems like it would solve the problem with minimal change to the language. Maybe there is a better way, or maybe we should move forward with it. What do you think? Fixing this problem would encourage attribute proliferation while facilitating correct use of attribute inference. [1] https://github.com/D-Programming-Language/phobos/pull/4082 [2] http://wiki.dlang.org/DIP79
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 14:55:00 UTC, Jakob Ovrum wrote: Maybe there is a better way, or maybe we should move forward with it. Maybe an alternative would be to simply ignore explicit attributes on templated functions, or at least ignore attributes on them applied with `attr:` or `attr { … }`. This could be a problem for `@trusted`.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 15:09:00 UTC, Jakob Ovrum wrote: On Saturday, 19 March 2016 at 14:55:00 UTC, Jakob Ovrum wrote: Maybe there is a better way, or maybe we should move forward with it. Maybe an alternative would be to simply ignore explicit attributes on templated functions, or at least ignore attributes on them applied with `attr:` or `attr { … }`. This could be a problem for `@trusted`. + 1 This seams very reasonable. When writing templates one should almost always rely on attribute inference. As for negation of attributes, I also support the approved by Andrei syntax: final(false), @nogc(useGC == AllocateGC.no), etc.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 15:09:00 UTC, Jakob Ovrum wrote: Maybe an alternative would be to simply ignore explicit attributes on templated functions That seems like a risky proposition. What if you mark some templates nogc to prevent inference on that. Then a future change causes an allocation. I would want to be notified.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 18:15:54 UTC, jmh530 wrote: On Saturday, 19 March 2016 at 15:09:00 UTC, Jakob Ovrum wrote: Maybe an alternative would be to simply ignore explicit attributes on templated functions That seems like a risky proposition. What if you mark some templates nogc to prevent inference on that. Then a future change causes an allocation. I would want to be notified. Right. Any @nogc caller code would cease to compile, but maybe the generic function is the entry point to a @nogc subportion of the program. As for the `default` approach, if we designed it to work with explicit attributes, like so: --- @safe: void foo(); void bar(T)(T t) default @nogc; // Infer pure, nothrow and @safe but require @nogc --- Then `default` wouldn't have that problem.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 15:09:00 UTC, Jakob Ovrum wrote: Maybe an alternative would be to simply ignore explicit attributes on templated functions, or at least ignore attributes on them applied with `attr:` or `attr { … }`. This could be a problem for `@trusted`. Please, no. Bulk application of attributes is very useful for templates, just like for regular code.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 18:39:54 UTC, Jakob Ovrum wrote: As for the `default` approach, if we designed it to work with explicit attributes, like so: --- @safe: void foo(); void bar(T)(T t) default @nogc; // Infer pure, nothrow and @safe but require @nogc --- Then `default` wouldn't have that problem. This could be OK, but it should work for bulk annotations, as well: @safe pure @nogc nothrow { void foo(); default @nogc { void bar(); void baz(); } } It's rather awkward, but better than what we have now.
Re: "default" keyword as function attribute
On Saturday, 19 March 2016 at 14:55:00 UTC, Jakob Ovrum wrote: We often repeat advice to put `@safe:`, or some other function attribute, at the top of your modules to apply the attribute en masse. In practice this quickly becomes infeasible. Sooner or later, a generic function is introduced to idiomatic D modules, and many of them, perhaps most of them, are more general when attribute inference is used. Any explicit attribute application disables inference of that attribute. In my experience this is by far the most common reason that blanket application of attributes is impractical. I'm not necessarily against an addition to the language that would make it easier to reset the attributes to their "defaults" when attribute: or attribute{} has been used, but I confess that in general, I'm inclined to think that folks should think twice before apply attributes en masse like that. It makes it _way_ too easy to miss that the attribute is being applied when it's somewhere else entirely in the file. As ugly as it is, in general, I think that it makes far more sense to be explicit about it and put @safe, nothrow, pure, etc. directly on the functions and not use : or {}. Personally, I only ever do it with access levels, which should generally be grouped together anyway IMHO, and even then, sometimes it's confusing about whether something is public or private without digging around elsewhere in the file to figure out whether a particular section is public or private. With @safe, pure, nothrow, etc., it's even worse, because it doesn't usually make sense to group functions based on those attributes, and you often do have to change one of those attributes on a particular function. It also makes it easy to accidentally apply attributes to templated functions, which is obviously bad. So, I'd honestly be inclined to argue that doing stuff like @safe: or pure: is bad practice. - Jonathan M Davis
Re: "default" keyword as function attribute
On Monday, 21 March 2016 at 22:58:35 UTC, Jonathan M Davis wrote: I'm inclined to think that folks should think twice before apply attributes en masse like that. Why? It makes it _way_ too easy to miss that the attribute is being applied when it's somewhere else entirely in the file. This isn't a problem for anything but @trusted.
Re: "default" keyword as function attribute
On Tuesday, 22 March 2016 at 02:05:20 UTC, Jakob Ovrum wrote: On Monday, 21 March 2016 at 22:58:35 UTC, Jonathan M Davis wrote: I'm inclined to think that folks should think twice before apply attributes en masse like that. Why? It makes it harder to know which attributes are actually being applied to a function, and it makes it way easier to accidentally apply attributes to a function. By putting them on the functions directly, it's very clear exactly which attributes apply, and you're not going to accidentally apply them to anything. And that becomes more critical as the file is maintained, because while you may know about all of those blanketed attributes when you first write the file, you may not realize that they're there later, and even if you do, someone else working on that file may not realize it. We've run into this with Phobos PRs where someone does the wrong thing, because they don't realize that an attribute has been applied to en masse. It makes it _way_ too easy to miss that the attribute is being applied when it's somewhere else entirely in the file. This isn't a problem for anything but @trusted. It's worse for @trusted, but it's a problem any attributes that are involved with attribute inference. By putting something like pure: or nothrow: in the file, you risk accidentally marking any function that uses attribute inference as having that attribute. And while the compiler will error out in many cases, if you're dealing with templates, it's far too easy to not catch the problem. Your unit tests may very well work perfectly fine with those attributes, whereas a different set of template arguments would fail to compile thanks to those accidentally applied attributes, and you won't catch it until you (or someone else using your code) tries to use that function with template arguments that don't work with those attributes. Another area where it causes problems is inheritance. Which attributes go on a base class function affect derived classes, possibly putting restrictions on derived classes that you don't want them to have. By using blanket attributes, it becomes easy to accidentally mark virtual functions as pure, nothrow, etc. and have those unit tests work just fine but then end up with someone else being screwed when they go to use that class, because those accidental attributes conflict with what they're trying to do. We have enough problems with making the right choices about which attributes go on virtual functions without having problems with them being applied accidentally. I can understand someone wanting to reduce the number of annotations that they need to put on declarations in D, but from what I've seen, blanket attributes are a maintenance problem, and I think that we're almost always far better off without them. You shouldn't have to search through the file to figure out which attributes apply to a function, otherwise you end up with an increase in the number of mistakes related to attributes, some of which will be quickly caught and many of which won't be. - Jonathan M Davis