What to do when you want to add attributes to your class functions?

Dukc ajieskola at gmail.com
Fri Sep 16 22:55:46 UTC 2022


On Friday, 16 September 2022 at 09:25:58 UTC, RazvanN wrote:
> Let's say you have a library class that exposes some methods. 
> At the beginning you did not focus on the safety, nogcness etc. 
> of your methods, you just wanted to have something working. You 
> publish your class, people start using it and now you are in a 
> phase where you would like your methods to be callable from 
> attributed contexts. So you go on and make your code safe, 
> nothrow, nogc, pure. However, now you are faced with a large 
> breaking change because suddenly you force your users to 
> respect these attributes.

As with anything, it's about finding the most practical solution 
overall for everyone involved. Unless you're publishing low-level 
system code (not very likely with classes), the usual 
cost-benefit radio from best to worst is IMO `@safe`, `pure`, 
`nothrow`, `@nogc`.

Considering a library done from stratch, I'd say that most 
abstract functions should have first two of those attributes but 
not the last two. But if you need to consider backwards 
compatibility, one option to consider is going only with `@safe`. 
Less breakage than with `@safe pure`, and breaking code can 
cowboy it with `@trusted // GREENWASHED: Not reviewed for safety` 
to each of those. Or better yet, actually review those functions 
for safety.

> This seems like a severe limitation to me.

It is a limitation, that's for sure. But I think it may be less 
severe than you think. Missing `nothrow` and `@nogc` attributes 
are far from the worst problems in a typical application code. 
Many would say that there they aren't even worth the visual 
clutter they are.

And if you don't mark your code `pure` and `@safe` well before 
you publish it for everyone to use in non-alpha state, it 
suggests that you don't consider even those attributes quite 
essential. It's arguable if that's a good attitude, but it's 
quite popular judging by this forum.


>
> It just seems simpler to never use attributes at all (with 
> classes).

That's close to a good advice with regards to `nothrow` and 
especially `@nogc`. I think that even if your abstract function 
should in principle be implemented without throwing or garbage 
collecting, it's often a good idea to omit those attributes just 
to make life easier for the child function implementor. Maybe 
even omit `pure`. But at least use `@safe` unless you have strong 
specific reasons not to (like heavy issues with backwards 
compatibility  - I'd probably defer adding `@safe` to next major 
version of the library). Making an abstract function `@system` 
puts much more burden to anyone who uses the class and cares 
about safety, than it saves burden from those implementing the 
children functions.

>
> Now, the entire point of this post is to ask what should we do 
> in the case of: https://github.com/dlang/dmd/pull/14432.

Disclaimer: I had only a surface look on what `Condition` seems 
to do. It's pretty likely I'm not on map on how it works and how 
it's supposed to be used.

I would not add `@nogc` to the interface of this function. A 
reasonable implementation might use the heap to do some 
bookkeeping and might want to allocate on `notify`. An ideal 
implementation would not do so, but abstract classes should 
generally be easy to implement even from not-so-perfect code.

It can be questioned why the same class acts both as an abstract 
class for other implementations, and an implementation in itself. 
If there was a separate `final class` that implemented 
`Condition`, it's members could be `@nogc`. The downside would be 
that the class instance would be a bit bigger since D object grow 
with number of interfaces/classes they inherit - maybe that's why.



More information about the Digitalmars-d mailing list