October 22 Re: package & protected? | ||||
---|---|---|---|---|
| ||||
On Monday, October 21, 2024 1:49:18 AM MDT Manu via Digitalmars-d wrote:
> So, a great many class members tend to be `protected`... that's just how
> classes are.
> We also avoid `friend` in D with `package`, which I find to often be quite
> useful.
>
> The trouble is... in a high number of cases where I want to make something `package`, it ALSO should be `protected`, but these 2 are mutually exclusive.
>
> This is a problem. We need a way to express both... what's the story here?
The story here is that you have to pick a single visibility attribute, and to get what you want, you'll have to work around the issue (which is possible). You can probably find multiple threads about this from several years ago (certainly, I recall there being discussions on this in the past), but for better or worse, visibility attributes can't be mixed. A symbol can have exactly one (this can be messed around with to a degree with aliases, but that tends to hit compiler bugs and/or poorly defined aspects of the language as a result).
Also, just like with private, package functions are non-virtual, so you can't override them. Rather than making visibility attributes super flexible, D made them simple, which simplifies a variety of things, and for the most part, it's a non-issue, but occasionally, it does get in the way depending on what you're trying to do. Probably a good part of why mixing protected and package in particular doesn't come up for a lot of people is that classes are typically avoided in idiomatic D code. Classes certainly get used, but structs and templates are used much more frequently than classes and virtual functions. And I don't think I've seen this particular issue brought up in years (though it has come up before).
In any case, the result is that if you want to have a virtual function, then you get to pick public or protected, and you can't make it private or package. And you can't restrict access to a function to a package and still have it be virtual. So, any solution needs to work within those restrictions.
One solution would be to create a package function which calls a protected function, essentially using a form of NVI. So, you'd have a virtual function that you can override that only that class, its derived classes, and the module that it's in could access while still having a function that other code within the package could access. And since the package function would be non-virtual and a one-liner, presumably, it wouldn't have any problems being inlined. You're stuck having two functions instead of one (along with needing a naming scheme to deal with the duplication), which is obviously less than ideal, but it seems like a straightforward solution to the problem given the current language limitations.
Another option would be to make the class package but make its functions public. In practice, that would basically be combining protected and package. The fact that the class would be restricted to the package would mean that the public visibility wouldn't truly be public, and since the functions would be public rather than package, they'd be virtual. Unlike the NVI solution, this wouldn't require any extra work on your part. However, if you wanted to do something like have a public class derived from the package class, then it obviously falls apart, because then the public visibility is actually public. Similarly, it's not going to work if you're looking to have the class be public but just restrict some of its API to the package. But as long as you're truly looking to restrict the class in question to a package, public is then effectively package protected.
Alternatively, you could just put all of this code in a single module instead of using a package, in which case, the rest of the code in the module could use the protected function, since everything within a module has access to protected functions just like it does with private, but that obviously messes with how you're organizing your code. If the amount of code involved is small enough, then it may just be simpler that way even if it means having larger modules, but if there's enough code involved, then presumably, it's not going to be a very good solution. So, I would guess that you're not going to want to go that route, but it is an option.
There may be other workarounds as well, but at the moment, that's all I can think of. Either way, there is no way to literally mark a function as both protected and package, since they're incompatible with the current design of the language.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation