June 09, 2019
On Sun, Jun 9, 2019 at 2:50 PM Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Sunday, 9 June 2019 at 21:35:19 UTC, Ola Fosheim Grøstad wrote:
> > On Sunday, 9 June 2019 at 21:13:50 UTC, Manu wrote:
> >> This is NOT polymorphism, we're not talking about polymorphism, I wish people would not change the topic.
> >
> > Well, it sort of is. Consider a situation where you have assignment defined for the super class, and where there is a field in the subclass that depends on a field in super.
>
> Or rather: you sometimes have a dependency, then you want the type system to prevent assignments through the base class. However, in other cases you don't have a dependency, then you do want to be able to assign through the base class.
>
> But you need something syntactical to tell the type system that such dependencies exist.

Such a dependency reeks of polymorphism-proper, maybe you're using the
wrong tool?
Anyone can write bad code... if your code is brittle in that way, then
you'll find out soon enough when someone does that!
It might also be impossible to inhibit direct assignment of the base.
There may be some practical limitations that we can design that make
such mistakes relatively less unlikely or easy to catch.

June 09, 2019
On Sun, Jun 9, 2019 at 3:05 PM Manu <turkeyman@gmail.com> wrote:
>
> On Sun, Jun 9, 2019 at 2:50 PM Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >
> > On Sunday, 9 June 2019 at 21:35:19 UTC, Ola Fosheim Grøstad wrote:
> > > On Sunday, 9 June 2019 at 21:13:50 UTC, Manu wrote:
> > >> This is NOT polymorphism, we're not talking about polymorphism, I wish people would not change the topic.
> > >
> > > Well, it sort of is. Consider a situation where you have assignment defined for the super class, and where there is a field in the subclass that depends on a field in super.
> >
> > Or rather: you sometimes have a dependency, then you want the type system to prevent assignments through the base class. However, in other cases you don't have a dependency, then you do want to be able to assign through the base class.
> >
> > But you need something syntactical to tell the type system that such dependencies exist.
>
> Such a dependency reeks of polymorphism-proper, maybe you're using the
> wrong tool?
> Anyone can write bad code... if your code is brittle in that way, then
> you'll find out soon enough when someone does that!
> It might also be impossible to inhibit direct assignment of the base.
> There may be some practical limitations that we can design that make
> such mistakes relatively less unlikely or easy to catch.

And here's the thing... this code ALREADY EXISTS in effect, except that it's way more hideous, and pointlessly aggravated (for the list of reasons above)!

There's a difference when something seems annoying once or twice, and
when it's been consistently annoying for 10 years with no sign that
patterns that leads to the situation are likely to change.
The errors and issues that the pattern in my OP cause, undoubtedly
outweigh any "but I thought of a gotcha!" you can think of... because
every such gotcha is already deployed, and coupled with the entire
experience being so much worse.

June 10, 2019
On Sunday, 9 June 2019 at 21:13:50 UTC, Manu wrote:
>
> Classic response.
>
> Because:
> 1, that sucks!
> 2, DRY; some structs have common elements. (how can anyone find that
> surprising?) I don't want to repeat them all over the place!

Wouldn't this be the same as having a struct of those elements, and having the struct as a variable of those structs? Alias this just takes that one step further and you don't even have to reference the struct that defines those elements.

> 3, syntax highlighting breaks from that point down !!!
> 4, debuginfo breaks from that point down !!!
> 5, debugging experience is embarrassing !!!

This is a larger problem with D. It is a complicated language like C++ but it has a very small community in comparison. Not sure about syntax highlighting, do you mean auto complete? Otherwise that'd be new. Haven't had debugging break from this style of mixin, though there is plenty wrong with D's debugging. A lot of these issues also apply to templates, though I wouldn't want that feature removed...

> 6, it depends on naming conventions (of the base object/function),
> which are brittle

Maybe explain this a bit more, so you'd want "override" to work with structs then? But you don't want the functions to be "virtual"?

> 7, meta to determine the base type is problematic and very complex if
> it wants to be accurate

With the mixin you could add an alias. It'd only work with structs that make use of the mixin, but I imagine you'd only want to to work with them anyways. At least I don't know any other library that uses this pattern, and I only need it for a few things in my codebase.



June 10, 2019
On 6/9/19 5:13 PM, Manu wrote:
> This is NOT polymorphism, we're not talking about polymorphism, I wish
> people would not change the topic.

The problem here is that it's difficult to define subtyping without polymorphism. C++ does technically allow it, but code such as:

struct my_vector : public std::vector<int> { ... }

is universally reviled. I really think it wouldn't help D much to add struct inheritance.
June 10, 2019
On Mon, Jun 10, 2019 at 12:30 AM Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 6/9/19 5:13 PM, Manu wrote:
> > This is NOT polymorphism, we're not talking about polymorphism, I wish people would not change the topic.
>
> The problem here is that it's difficult to define subtyping without polymorphism. C++ does technically allow it, but code such as:
>
> struct my_vector : public std::vector<int> { ... }
>
> is universally reviled. I really think it wouldn't help D much to add struct inheritance.

We do it anyway though, it's just terrible.
How will it cause any harm to anybody? I hate this idea that something
has shown to be sorely missed for so long, and we still can't
reconsider it because some moron out there might write bad code?
D almost exclusively attracts power-users, who have unbelievably
complex software to get on with. Tools are good, especially tools like
this which only make a shitty piece of existing language much cleaner
and simpler to reason about.
June 10, 2019
On Monday, 10 June 2019 at 07:26:29 UTC, Andrei Alexandrescu wrote:
> On 6/9/19 5:13 PM, Manu wrote:
>> This is NOT polymorphism, we're not talking about polymorphism, I wish
>> people would not change the topic.
>
> The problem here is that it's difficult to define subtyping without polymorphism. C++ does technically allow it, but code such as:
>
> struct my_vector : public std::vector<int> { ... }
>
> is universally reviled. I really think it wouldn't help D much to add struct inheritance.

Not a the best example. Inheriting from your own vector implementation is fine, except that C++ has a weak and broken type system, so templated inheritance does not work properly (you have to list all the members you want visible in the subclass which is very annoying).

Inheriting from the standard C++ library is bad because:
- the type was not designed with inheritance in mind
- the type may have new members added since it is in the standard library
- the compiler might special case it, since it is the standard library

Anyway, lots of things that are "universally reviled" in C++ is related to weaknesses in the C++ language design/type system.

June 10, 2019
On Sunday, 9 June 2019 at 22:05:48 UTC, Manu wrote:
> Such a dependency reeks of polymorphism-proper, maybe you're using the wrong tool?
> Anyone can write bad code... if your code is brittle in that way, then
> you'll find out soon enough when someone does that!

Well, I was speaking in general, not really related to my code ;-).

In the general case you would want a strict type system (well unless you mark a region as bypassing the type system). C++ inherited a weak type system from C and has tried to make it stricter, but with quite a bit of weirdness.

Type systems are difficult to design, and very difficult to evolve one piece at a time…

> It might also be impossible to inhibit direct assignment of the base.
> There may be some practical limitations that we can design that make
> such mistakes relatively less unlikely or easy to catch.

Absolutely, you have to list all the use cases you want to cover. Then look for a solution.

The best solution would probably require constraint based sub-typing combined with some kind of flow-typing, but that is out of reach, so something simpler will have to do.

A key point that is often missed in such discussions is that for code to be readable, you should be able to tell "roughly" what a data structure is all about by glancing at it. Which is itself is a good reason to provide inheritance.

Anyway, you might need language changes to allow inheritance with "merging":

struct A { char a; /* 3 unused bytes */ double b; }
struct B : A { char c; }

Should result in { char a; char c; /*3 unused bytes*/ double b;}

But that will fail if assignment to A is done with blitting.

So, I am bit sceptical of evolving languages in the way that C++/D evolves. C++ has a problem with installed base, though, so it is "maintenance mode"… D does not really have that problem.

June 10, 2019
On Sunday, 9 June 2019 at 22:13:51 UTC, Manu wrote:
> And here's the thing... this code ALREADY EXISTS in effect, except that it's way more hideous, and pointlessly aggravated (for the list of reasons above)!

Yes, I agree that reasonable ways of composing datastructures  should be readable at a glance and shared across all programs. So metaprogramming solutions that does not make code legible is not a good answer.

For instance, mixins are good for adding "interface like" methods, but if you start using it fore general composition then we are back in macro-land where everything is possible, but intent is indistinguishable. The code will start to look like a soup of syntax…

By using macroish features then you cannot easily grasp the intent.
With inheritance the intent is crystal clear, even for newbies.

Absolutely.


June 10, 2019
On Sunday, 9 June 2019 at 22:03:02 UTC, Manu wrote:
> to inhibit the worst of them, but the current restriction is anti-productive, the line in the sand is drawn incorrectly.

Well, you are arguing in favour of something that I have argued for in the past as well, so I am inclined to agree with you :-).

On the positive side, other features that I've argued for in the past seems to be implemented now… so who knows.

Anyway, designers are not inclined to change their mind easily. So the best thing you can do is to put the arguments on the table and make a good case for it. After a while people will internalize your arguments as long as they are listening.

Then wait a few years, then they forget where the arguments came from and perceive it as their own.

So, as long people listen to your arguments, then changes might come… with patience.

I like some of the new directions that I see, but I am not that patient…

I think there would be more progress if D focused on bringing the language to embedded programming, instead of having such a wide range of concerns (e.g. scripting language like abilities).

> For contrast, I've been arguing on bug reports recently that people
> think interactions with uninitialised unions (or =void initialised
> code) is @safe... 🤯🤯🤯
> which just shows how astonishingly arbitrary this shit is.

I don't think @safe is possible with this approach, and frankly, it doesn't really matter all that much. What matters is that the design is such that the programmer groks that a piece of code is potentially unsafe. I consider C-style unions to be a low level feature…


June 10, 2019
On 6/9/2019 3:03 PM, Manu wrote:
> I can form a misuse fail for practically any language feature.
> It's possible we identify some common-sense restrictions here to
> inhibit the worst of them, but the current restriction is
> anti-productive, the line in the sand is drawn incorrectly.

Everyone, and I mean everyone, who misuses a feature is thoroughly convinced their use is productive. For an ancient example:

    #define BEGIN {
    #define END }

Yep. That. :-) And it's not remotely the worst abuse of the preprocessor I've seen, all of which are stoutly defended.


> For contrast, I've been arguing on bug reports recently that people
> think interactions with uninitialised unions (or =void initialised
> code) is @safe... 🤯🤯🤯
> which just shows how astonishingly arbitrary this shit is.

Uninitialized non-pointers are @safe, because @safe refers to memory safety, not "no bugs". Perhaps I was wrong to define it that way, but it is deliberate, and not arbitrary.