Sealed classes - would you want them in D?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue May 15 07:23:55 UTC 2018


On Tuesday, May 15, 2018 06:38:04 KingJoffrey via Digitalmars-d wrote:
> On Tuesday, 15 May 2018 at 05:59:44 UTC, Mike Parker wrote:
> > You can keep your grouping and get your strict encapsulation
> > like so:
> >
> > // foo/bar/baz/package.d
> > module foo.bar.baz;
> > public import
> >
> >     foo.bar.baz.a,
> >     foo.bar.baz.b,
> >     foo.bar.baz.c,
> >     foo.bar.baz.funcs;
> >
> > The client need neither know nor care that everything is in
> > separate modules and you get your strict encapsulation. You can
> > still share items between modules via package protection, and
> > within specific package hierarchies via package(packageName).
> > And even better, you now have less code per module to reason
> > about (re: one of your earlier arguments against the current
> > behavior).
>
> Fine. If I take your solution above, and ensure that every class,
> goes into it's own module, and that a module containing a class,
> contains nothing other than a single class (i.e no free
> functions), then sure, I end up where I am now, with C++/Java/C#
> - i.e a good place, where I feel comfortable. My declared
> interface is respected.
>
> Why do I need D then?

I honestly don't see how D deals with private should be a major factor in
deciding what language to use. Even if you see how D handles private to be
negative, if its other features aren't appealing enough to make you want to
use it in spite of what's going on with private, I don't see why what
happens with private matters. And even if private worked the way you want it
to, I don't see why that would make anyone want to use the language over C++
or Java or whatnot. How stuff like private, package, and friends are dealt
with certainly has an impact on a language, but it's just one piece of many,
and I would expect most people to think that it was a relatively small piece
of the puzzle such that it would not be a major deciding factor in whether
they use the language, whether they like what was done with access levels or
not.

> i.e. under what circumstances, would I want
> to put something extra into the module, so that it can abuse the
> declared interface of my class?

The declared interface to your class is what's presented to everything
outside of your module. Everything inside the module has full access just
like any friend would in C++. That's basically how you have to think about
it. As long as you insist that the class itself is the barrier, then you're
never going to be anything but unhappy with D's approach.

> Can you give me some examples?

The prime one is unit tests. The fact that they can access the private
variables is invaluable for testing the state of an object. In C++, I have
always have to make all of the tests friends of the class so that they can
access the internals for testing. In D, I don't have to worry about any of
that, and the tests don't affect the public interface of the class at all.

Also, there are plenty of cases where it's nice to be able to have private
functions which can access the internals of a class - and you don't
necessarily want them to be members of the class. This is particularly true
when the class is templated. e.g. dxml provides a fairly simply public API
in dxml.parser, but it has lots of private helper functions which access the
members of the struct. They operate on stuff that isn't supposed to be
publicly available, and it's cleaner to have them outside the struct where
they can be tested separately from the struct.

Also, why would I necessarily care if something else in the same module can
access the private members of a struct or class? If they're associated
closely enough to be put in the same module, then there's frequently no
reason to care if they access the private members or not, and as long as
you're dealing with stuff like getters and setters, unless they're doing
extra work other than simply encapsulating access to a member variable,
there really isn't a reason why it would be a problem for other stuff in the
module to access the member variable directly. Everything in the module goes
together, and you can easily change anything in there if you need to due to
something changing in the internals of the struct or class, and it won't
affect the public API. Everything in the module is internal.

Particularly when you're talking about private functions, whether something
is in the class itself or in the module is an implementation detail and
largely irrelevant. And if you have a public free function that can access
the class' internals, well that function is associated with the class by
being in the same module just like a friend function would be, and you get
all of the benefits that you'd get with a friend function without having to
explicitly declare everything as friends. So, all of the same reasoning as
to why you'd want a friend function applies to why it can be valuable to
have something in the same module access the internals of a class. The only
cost is that you can't declare something not to be a friend and have it be
in the same module, and you can't declare it to be a friend when it's in
another module (though package does provide similar functionality). The
assumption is that anything that goes in the same module can either
reasonably be treated as friends, or it doesn't matter if they are.

Basically all of the same arguments that you're giving against having
everything in the module being treated as friends of each other can be given
against having friends in the first place. It's just that D makes it
implicit within the module.

- Jonathan M Davis



More information about the Digitalmars-d mailing list