package & protected?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Oct 22 13:47:51 UTC 2024


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





More information about the Digitalmars-d mailing list