Using closure in function scope to make "real" private class members
Andrey Zherikov
andrey.zherikov at gmail.com
Tue Jun 7 18:07:34 UTC 2022
On Tuesday, 7 June 2022 at 14:04:27 UTC, Ola Fosheim Grøstad
wrote:
> Hi, the benfits of encapsulation is obvious, but you can
> encapsulate without having language support. If you want
> class-private, just choose the convention that "_fieldname"
> means class-private. Every time you see "obj._fieldname" you
> will realize that this is not what you want to do. If that is
> not enough, use static analysis.
>
> The reality is, encapsulation does not have to be in the
> language at all in order for you to have encapsulation. It can
> be a mental thing/code review thing, it can be a grammar thing,
> it can be a linter issue.
>
> Python does not provide in-language encapsulation at all. Yet I
> encapsulate my classes in Python all the time. And I have
> external tools to check for it if I want.
What you are speaking here about is encapsulation by convention
(naming rules for the members). This is good approach especially
when everyone follows it. Unfortunately people don't. They tend
to code their own way. As a result, for the languages that don't
provide encapsulation (like Python), people started adding
corresponding checks to static analyzers/linters to force the
encapsulation. So the convention became more complex: in addition
to naming rules, now you should also run static analyzer/linter.
This means that the code that violates encapsulation is valid but
breaks some convention rules.
For the languages that have encapsulation forced by compiler, you
have a guarantee that it's not broken. In this case the code that
violates encapsulation is not valid and must be fixed.
Just to summarize, both approaches (no encapsulation and forced
encapsulation) are equally good. We all have our habits in coding
and it doesn't mean that everyone should do the things in the
only one way.
As for me, I'd like to see class/struct level encapsulation in D.
Let me share my D experience to clarify the benefit. I started
writing a (single module) library that can be used by others. At
that point I wanted to separate public API from internal code so
I used `private` for everything internal and `public` for public
API. At some point during active development, the module became
so large so I decided to convert it to a package and split into
logical components (modules). So I can easily enforce clear
interaction between logical components by `package` and
`private`. Now I want to enforce clear interaction between
physical components (structs and classes) within a logical
component. Ideally, I want to be able to mark specific members as
"real" private so nothing else except struct/class itself can
access them. This is what I see as a benefit of this feature for
me.
Unfortunately, D gives me two options: put every struct/class
into its own module (sub module of a logical component), or leave
it as is. Since I am not a fan of having dozens of small files
(one per struct/class), I decided to leave it as is.
Regarding implementation. I don't like `@private` as people will
be confused a lot with `@private`<->`private`. IMHO the ideal
solution would be having `module` to mark module privates and
`private` for real privates but this is not backward compatible.
So the better solution might be extending syntax for `private`
having something like `private(symbol[, symbol ...])` where
`symbol` is a symbol that has access to the member For example:
`this` means current struct/class; `this.foo` or
`<typeof(this)>.foo` means foo member in the current struct/class.
More information about the Digitalmars-d
mailing list