www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - "default" keyword as function attribute

reply Jakob Ovrum <jakobovrum gmail.com> writes:
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(<boolean 
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
Mar 19 2016
next sibling parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
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`.
Mar 19 2016
next sibling parent ZombineDev <petar.p.kirov gmail.com> writes:
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.
Mar 19 2016
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
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.
Mar 19 2016
parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
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.
Mar 19 2016
parent tsbockman <thomas.bockman gmail.com> writes:
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.
Mar 19 2016
prev sibling parent tsbockman <thomas.bockman gmail.com> writes:
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.
Mar 19 2016
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Mar 21 2016
parent reply Jakob Ovrum <jakobovrum gmail.com> writes:
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.
Mar 21 2016
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Mar 21 2016