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