June 09, 2022

On Thursday, 9 June 2022 at 10:39:17 UTC, Dom Disc wrote:

>

Whatever you do, it needs to be something human-readable, because the compiler can't help you there.

Yes, although for C++ private + friend is helpful. I actually would want friend in C++ to be more limiting, so that you could say "this function is allowed to call this member, but nothing else". Mostly relevant for concurrency issues, could be useful in that context as finding such bugs is extremely time consuming.

Tighter encapsulation is valuable when you change/restructure your codebase, but it equally important to have clean syntax that is easy to read!

>

If something is convoluted, you need to sort it out and split into two modules. Another protection level won't help.

I would not want to write such convoluted modules, but maybe others do.

>

Because, as I said, a new level won't reduce your effort to understand whats happening, you still need to inspect everything within the file. But splitting would help a lot with that.

You don't have to inspect everything in the file. For instance, in C++ I often let an inner class (class within a class) be protected against methods in the outer class.

Also, in Simula a class and module was the same construct. A class was used to represent what D uses a module for.

> >

If someone ever started on D3, that is the place to start IMO.

Sorting things out should be possible without need for an new fork. It should be done withing the actual phobos as it wouldn't change the interface (at least not much).

So this is my perspective:

Phobos is one of those «larger» codebases where people have made an effort to use D constructs to write «good» code to the best of their ability. We cannot expect better for the average D programmer. So that is a realistic picture of what D code over time will look like.

As such, one can study it to figure out where the language has room for improvement. You could also improve on Phobos, but that is less important (if it works).

June 09, 2022

On Thursday, 9 June 2022 at 10:40:01 UTC, bauss wrote:

>

[...]

Might as well just make everything public then, right? Why stop there. Removing private, protected, package etc. is the way to go then?

[...]

I still don't understand why people still don't get this: The module is the unit of encapsulation in D. If you want your class to be truly inaccessible, put it in its own module. Don't follow Phobos' example: Keep your modules small.

June 09, 2022
On Thursday, 9 June 2022 at 10:40:01 UTC, bauss wrote:

> Might as well just make everything public then, right?
No. I have written reducing the search-space to one file *DOES* reduce the effort.
But reducing it to a part of a file (which class level privacy would do) does not, because still all member-functions that shouldn't have access to the privates still have to be reviewed. You still have to search the whole file to find all usages of private variables, so you gain nothing.

> Why stop there. Removing private, protected, package etc. is the way to go then?
Nonsense. Nobody wants that.

> the point of it all is to cut down the amount of code you have to review.
Yup. And the reduction gained by class level in addition to module level (which is not available in C++) is neglictable.

> There's no reason to do the analysis yourself if the compiler can do it for you in 99% of the cases.
But it can't. You have to check the member functions manually anyway.
On module level you have to additionally check the handful of function that are also in the same file. But in C++ instead you have to check the additionally friends, which may be scattered all over the whole project.

So in comparison with C++ module level privacy is just better (if you don't put everything in one file).
Within D alone, we would gain nearly nothing by an additional level.

June 09, 2022

On Thursday, 9 June 2022 at 10:59:53 UTC, Mathias LANG wrote:

>

On Thursday, 9 June 2022 at 10:40:01 UTC, bauss wrote:

>

[...]

Might as well just make everything public then, right? Why stop there. Removing private, protected, package etc. is the way to go then?

[...]

I still don't understand why people still don't get this: The module is the unit of encapsulation in D. If you want your class to be truly inaccessible, put it in its own module. Don't follow Phobos' example: Keep your modules small.

But it doesn't always work putting your class in another module.

Because sometimes it's not all members you want to restrict access to, but only some.

And also there are some scenarios where it doesn't even work properly when put into your own module.

Here is an example where it does not work:

a.d

module a;

class Foo
{
	private:
	int _c;
}

import b;
void handle(Bar child)
{
	// This fails even tho we're in module a,
	// so _c should be available to us, because
	// _c is private to the module (but not really.)
	child._c += child.c;
}

b.d

module b;

import a;

class Bar : Foo
{
	public:
	int c;

	this(int c)
	{
		this.c = c;
	}
}

main.d

module main;

import a;
import b;

void main()
{
	auto bar = new Bar(30);
	handle(bar);
}

The above fails to compile.

However this works:

a.d

module a;

class Foo
{
	private:
	int _c;
}

class Bar : Foo
{
	public:
	int c;

	this(int c)
	{
		this.c = c;
	}
}

void handle(Bar child)
{
	// It's okay now since Bar is in the a module.
	child._c += child.c;
}

(main.d is the same)

So you can't always split classes into new modules that easily.

It really should work in both cases since we're both accessing _c from within the module, but there's clearly a difference.

June 09, 2022
On Thursday, 9 June 2022 at 11:04:31 UTC, Dom Disc wrote:
> On Thursday, 9 June 2022 at 10:40:01 UTC, bauss wrote:
>
>> Might as well just make everything public then, right?
> No. I have written reducing the search-space to one file *DOES* reduce the effort.
> But reducing it to a part of a file (which class level privacy would do) does not, because still all member-functions that shouldn't have access to the privates still have to be reviewed. You still have to search the whole file to find all usages of private variables, so you gain nothing.
>
>> Why stop there. Removing private, protected, package etc. is the way to go then?
> Nonsense. Nobody wants that.
>
>> the point of it all is to cut down the amount of code you have to review.
> Yup. And the reduction gained by class level in addition to module level (which is not available in C++) is neglictable.
>
>> There's no reason to do the analysis yourself if the compiler can do it for you in 99% of the cases.
> But it can't. You have to check the member functions manually anyway.
> On module level you have to additionally check the handful of function that are also in the same file. But in C++ instead you have to check the additionally friends, which may be scattered all over the whole project.
>
> So in comparison with C++ module level privacy is just better (if you don't put everything in one file).
> Within D alone, we would gain nearly nothing by an additional level.

I don't know why you keep mentioning C++ and how D improves over C++.

Nobody mentioned C++, I certainly didn't and I really don't care if D improves over C++ or not or what their differences are.

I'm not a C++ programmer and I don't come from a C++ background.
June 09, 2022

On Thursday, 9 June 2022 at 11:28:57 UTC, bauss wrote:

>

On Thursday, 9 June 2022 at 10:59:53 UTC, Mathias LANG wrote:

>

On Thursday, 9 June 2022 at 10:40:01 UTC, bauss wrote:

>

[...]

Might as well just make everything public then, right? Why stop there. Removing private, protected, package etc. is the way to go then?

[...]

I still don't understand why people still don't get this: The module is the unit of encapsulation in D. If you want your class to be truly inaccessible, put it in its own module. Don't follow Phobos' example: Keep your modules small.

But it doesn't always work putting your class in another module.

Because sometimes it's not all members you want to restrict access to, but only some.

And also there are some scenarios where it doesn't even work properly when put into your own module.

Here is an example where it does not work:

a.d

module a;

class Foo
{
	private:
	int _c;
}

import b;
void handle(Bar child)
{
	// This fails even tho we're in module a,
	// so _c should be available to us, because
	// _c is private to the module (but not really.)
	child._c += child.c;
}

b.d

module b;

import a;

class Bar : Foo
{
	public:
	int c;

	this(int c)
	{
		this.c = c;
	}
}

main.d

module main;

import a;
import b;

void main()
{
	auto bar = new Bar(30);
	handle(bar);
}

The above fails to compile.

However this works:

a.d

module a;

class Foo
{
	private:
	int _c;
}

class Bar : Foo
{
	public:
	int c;

	this(int c)
	{
		this.c = c;
	}
}

void handle(Bar child)
{
	// It's okay now since Bar is in the a module.
	child._c += child.c;
}

(main.d is the same)

So you can't always split classes into new modules that easily.

It really should work in both cases since we're both accessing _c from within the module, but there's clearly a difference.

Here's a relevant dead DIP for this:

https://wiki.dlang.org/DIP22

As noted, D doesn't even know what private should mean as it certainly doesn't mean "private to the module" only.

June 09, 2022
On Thursday, 9 June 2022 at 10:39:17 UTC, Dom Disc wrote:
> ....
> Jup. But new privacy-levels are no solution to them.
> ..

Authorisation and access control, are integral to OOP. Always has been, always will be.

Any 'new' privacy-level, would only be 'new' to D ;-)

C++ had the 'friend' issue.

D solved that. Horray! Let's just make everyone 'forever' friends.

Now D has the 'unfriend' issue.

June 09, 2022
On Thursday, 9 June 2022 at 10:03:02 UTC, Dom Disc wrote:
>
> ...
> I still don't get why class level encapsulation should be any better than module level encapsulation.

Well, it's not necessarily better - either way.

If I can encapsulate one concept well, within a class, why must I be forced to expand my 'encapsulation barrier' to the module.

What have I achieved in doing that?

I mean even a function in a module has a better encapsulation barrier than a class! Well, even an int does - you can't just put "wtf!" into an int. An int has a set of invariants that must be maintained, and are, by the compiler.

Smaller abstraction are easier to reason about too.

An encapsulation barrier at the module level, is also very useful.

But it should be your design decision, not the language forcing it onto you.

With the proper access levels (i.e scope level privacy), the problem just goes away...no need to do silly workarounds.

June 09, 2022
On Thursday, 9 June 2022 at 12:42:22 UTC, forkit wrote:
> On Thursday, 9 June 2022 at 10:03:02 UTC, Dom Disc wrote:
>> [...]
>
> Well, it's not necessarily better - either way.
>
> If I can encapsulate one concept well, within a class, why must I be forced to expand my 'encapsulation barrier' to the module.
>
> What have I achieved in doing that?
>
> I mean even a function in a module has a better encapsulation barrier than a class! Well, even an int does - you can't just put "wtf!" into an int. An int has a set of invariants that must be maintained, and are, by the compiler.
>
> Smaller abstraction are easier to reason about too.
>
> An encapsulation barrier at the module level, is also very useful.
>
> But it should be your design decision, not the language forcing it onto you.
>
> With the proper access levels (i.e scope level privacy), the problem just goes away...no need to do silly workarounds.

If you don't want members to be visible to the whole module, why do you insist on putting the class definition into the module scope in the first place? just put it inside a function.
June 09, 2022

On Thursday, 9 June 2022 at 12:42:22 UTC, forkit wrote:

>

But it should be your design decision, not the language forcing it onto you.

In an ideal world, yes. In the practice you have to think about the limitations of the language when you do modelling.

All the C dialects come with their own set of limitations… If you compare D to other C-dialects the orignal D quality was to be more simple than languages such as C++ and Objective-C++.

As such, the module-level thinking is a simplification. Other aspects of the language has broken with the "make it simple" vision, which is unfortunate, but difficult to undo.

To a large extent this feature-creep is due to giving in to demands and whims and not resisting ideas that are "not simpler".

I guess you could argue that resisting class-privacy is the wrong feature to resist, but objectively speaking: D should absolutely resist more feature bloat and only give in where it truly matters.