October 20, 2019
On Sunday, 20 October 2019 at 09:31:34 UTC, Max Samukha wrote:
> On Saturday, 19 October 2019 at 22:14:55 UTC, Meta wrote:
>
>>
>> It's not a defect. Interfaces have no state, so it doesn't matter which is called. Java does the same thing.
>
> What do you mean by 'have no state'? If Java does the same thing, it does it wrong. Nominal typing is all about avoiding structural conflicts. Members coming from different nominal types should not be conflated.

Interfaces in D do not have any state, i.e., they're not allowed to declare member variables that implementing classes inherit, and they don't define any implementation for implementing classes to inherit - they just define the interface (this has recently changed in Java now that interfaces can define methods with a default implementation, thus Java now provides a way to disambiguate if two different interfaces declare default methods with the same name).

Because classes do not inherit any state or implementation from interfaces, if you have, say, the following class:

class ImplementsBoth: Display, Debug { void fmt(){} }

And you do `new ImplementsBoth().fmt()`, it really doesn't matter whether the fmt you're calling is Display's fmt, or Debug's, because there is no interface state or inherited implementation that would change fmt's behavior by calling one or the other.

The fact that interfaces carry no state or default implementaion is also why they don't have the diamond inheritance problem that C++'s multiple inheritance can cause.

So semantically, collapsing Display.fmt and Debug.fmt into one is perfectly valid. I agree it might be nice to allow disambiguating in certain cases, but that would be an enhancement, not a bug.

https://en.m.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

October 20, 2019
On Sunday, 20 October 2019 at 17:11:27 UTC, Meta wrote:
> On Sunday, 20 October 2019 at 09:31:34 UTC, Max Samukha wrote:
>> [...]
>
> Interfaces in D do not have any state, i.e., they're not allowed to declare member variables that implementing classes inherit, and they don't define any implementation for implementing classes to inherit - they just define the interface (this has recently changed in Java now that interfaces can define methods with a default implementation, thus Java now provides a way to disambiguate if two different interfaces declare default methods with the same name).
>
> [...]

They don't carry state, but they surely carry semantics hence why some languages allow to clarify the implementations.

Because passing implementation B to a method expecting implementation A can lead to hard to track down errors.



October 20, 2019
On Sunday, 20 October 2019 at 17:34:17 UTC, Paulo Pinto wrote:
> On Sunday, 20 October 2019 at 17:11:27 UTC, Meta wrote:
>> On Sunday, 20 October 2019 at 09:31:34 UTC, Max Samukha wrote:
>>> [...]
>>
>> Interfaces in D do not have any state, i.e., they're not allowed to declare member variables that implementing classes inherit, and they don't define any implementation for implementing classes to inherit - they just define the interface (this has recently changed in Java now that interfaces can define methods with a default implementation, thus Java now provides a way to disambiguate if two different interfaces declare default methods with the same name).
>>
>> [...]
>
> They don't carry state, but they surely carry semantics hence why some languages allow to clarify the implementations.
>
> Because passing implementation B to a method expecting implementation A can lead to hard to track down errors.

I'm not saying that allowing to differentiate between implementations would be worthless, just that it's not a bug that D collapses them into 1 in the implementing class.
October 20, 2019
On Sunday, 20 October 2019 at 17:46:07 UTC, Meta wrote:

>
> I'm not saying that allowing to differentiate between implementations would be worthless, just that it's not a bug that D collapses them into 1 in the implementing class.

I still do not follow why the diamond problem and the lack of data members is relevant. For me, it is not different from:

struct A {
    int x;
}

struct B {
    int x;
}

Both types are isomorphic to int, but we still consider them distinct types and x's inside them unrelated, even though they are typed and named identically.

October 20, 2019
On Sunday, 20 October 2019 at 17:46:07 UTC, Meta wrote:
> On Sunday, 20 October 2019 at 17:34:17 UTC, Paulo Pinto wrote:
>> On Sunday, 20 October 2019 at 17:11:27 UTC, Meta wrote:
>>> On Sunday, 20 October 2019 at 09:31:34 UTC, Max Samukha wrote:
>>>> [...]
>>>
>>> Interfaces in D do not have any state, i.e., they're not allowed to declare member variables that implementing classes inherit, and they don't define any implementation for implementing classes to inherit - they just define the interface (this has recently changed in Java now that interfaces can define methods with a default implementation, thus Java now provides a way to disambiguate if two different interfaces declare default methods with the same name).
>>>
>>> [...]
>>
>> They don't carry state, but they surely carry semantics hence why some languages allow to clarify the implementations.
>>
>> Because passing implementation B to a method expecting implementation A can lead to hard to track down errors.
>
> I'm not saying that allowing to differentiate between implementations would be worthless, just that it's not a bug that D collapses them into 1 in the implementing class.

Sure, one can argue that it's not a bug, auto-decoding isn't a bug, in fact it was very much intentional. But I think we'd all be better off without it. The way it is implemented can lead to bugs quite easily. Since it picks whichever one based on order. None of this is obvious. Rationale like your's is why the bug reports like this one remain open for 9+ years and it never gets fixed. It's not a bug it's a feature! Therefore any change is an enhancement and requires a DIP.
October 21, 2019
On Friday, 18 October 2019 at 16:07:43 UTC, Atila Neves wrote:

> I agree and support all of this. I know that dmd as a library right now can only be used from dub with `~master`. What is the technical reason stopping a version number again?

Dub needs a Git tag and it needs to follow semantic versioning, otherwise Dub will ignore it. The tags for the compiler do not follow semantic versioning. There's no technical reason. It's just that the compiler releases doesn't follow the semantic versioning model. Any release can break anything, basically.

I suggested a workaround until the compiler properly follows the semantic versioning model. Which is to add two tags for each new release. One that we already add today. The other one would be explicitly intended only for the library and would be `0.x.0` and we increment `x` by one for each release. Since the `0.x.y` versions have special meaning, it's for the initial development. Semantic versioning says:

"Anything MAY change at any time. The public API SHOULD NOT be considered stable."

Nothing happened with that with that suggestion.

--
/Jacob Carlborg
October 21, 2019
On Monday, 21 October 2019 at 09:45:08 UTC, Jacob Carlborg wrote:
> On Friday, 18 October 2019 at 16:07:43 UTC, Atila Neves wrote:
>
>> I agree and support all of this. I know that dmd as a library right now can only be used from dub with `~master`. What is the technical reason stopping a version number again?
>
> Dub needs a Git tag and it needs to follow semantic versioning, otherwise Dub will ignore it. The tags for the compiler do not follow semantic versioning. There's no technical reason. It's just that the compiler releases doesn't follow the semantic versioning model. Any release can break anything, basically.
>
> I suggested a workaround until the compiler properly follows the semantic versioning model. Which is to add two tags for each new release. One that we already add today. The other one would be explicitly intended only for the library and would be `0.x.0` and we increment `x` by one for each release. Since the `0.x.y` versions have special meaning, it's for the initial development. Semantic versioning says:
>
> "Anything MAY change at any time. The public API SHOULD NOT be considered stable."
>
> Nothing happened with that with that suggestion.
>
> --
> /Jacob Carlborg

+1 to this, it makes a lot more sense than my idea of simply dropping the 0 and having a fake semantic versioning that follows the current one.

When I tried using DMD as a library, as a workaround I had to set it up as a git submodule, with an explicit path for dub.
October 21, 2019
On Sunday, 20 October 2019 at 19:58:28 UTC, Max Samukha wrote:
> On Sunday, 20 October 2019 at 17:46:07 UTC, Meta wrote:
>
>>
>> I'm not saying that allowing to differentiate between implementations would be worthless, just that it's not a bug that D collapses them into 1 in the implementing class.
>
> I still do not follow why the diamond problem and the lack of data members is relevant. For me, it is not different from:
>
> struct A {
>     int x;
> }
>
> struct B {
>     int x;
> }
>
> Both types are isomorphic to int, but we still consider them distinct types and x's inside them unrelated, even though they are typed and named identically.

This is interesting. Can you provide a source of why the nominal type system is a contradiction to the current approach?
I mean, currently I can follow Meta more:
If you have an object implementing both, Debug and Display, then the class has to implement foo. And if it does, it can be handled by functions both handling Debug and Display. The ambiguity is solved at this level:

´´´
interface De{ void foo(); }
interface Di { void foo(); }
class C : De, Di{ override void foo(){} }
void main()
{
    auto c = new C();
    //c.fun1; //fails to compile, as you would expect
    De de = c;
    Di di = c;
    de.fun1;
    di.fun1;
}
auto fun1(De de){ de.foo; }
auto fun1(Di di){ di.foo; }
´´´

So, for sure, if you want to have different overloads for different interfaces, then, they can't go into the class of C. But there is no need to do so.
October 21, 2019
On Sunday, 20 October 2019 at 20:41:01 UTC, Exil wrote:
> Sure, one can argue that it's not a bug, auto-decoding isn't a bug, in fact it was very much intentional. But I think we'd all be better off without it. The way it is implemented can lead to bugs quite easily. Since it picks whichever one based on order.

Show me a concrete example. Also, there is no "picking" of which interface method is implemented. Both are implemented by the same method.

> None of this is obvious.

I agree. I was surprised as well when I first learned about this, but that doesn't mean it's incorrect.

> Rationale like your's is why the bug reports like this one remain open for 9+ years and it never gets fixed. It's not a bug it's a feature! Therefore any change is an enhancement and requires a DIP.

There's this other language called Java that you may have heard of, that does things the exact same way, and the many millions of programmers that use that language seem to have no issue with this behaviour. I've already agreed that it would be worth having a way to write a different implementation for different interfaces with the same method, but that is the very *definition* of an enhancement.
October 21, 2019
On Monday, 21 October 2019 at 12:34:14 UTC, Meta wrote:
> On Sunday, 20 October 2019 at 20:41:01 UTC, Exil wrote:
>> Sure, one can argue that it's not a bug, auto-decoding isn't a bug, in fact it was very much intentional. But I think we'd all be better off without it. The way it is implemented can lead to bugs quite easily. Since it picks whichever one based on order.
>
> Show me a concrete example. Also, there is no "picking" of which interface method is implemented. Both are implemented by the same method.

interface OneThing {
    void foo(); // should do One thing
}

interface AnotherThing {
    void foo(); // do another thing
}

class A : OneThing, AnotherThing {
    override void foo() { }
}


void bar(OneThing o) {
   o.foo(); // do something unrelated to AnotherThing
}

void tar(AnotherThing a) {
   a.foo(); // do something unrelated to OneThing
}


void main() {
    A a = new A;

    bar(a);
    tar(a);
}


Your assumption is that just because the functions are named the same thing then they should do the exact same thing. Sure you can avoid naming conflict when you have to, but if you are using two libraries you didn't write then you can't make those kinds of decisions.


>> None of this is obvious.
>
> I agree. I was surprised as well when I first learned about this, but that doesn't mean it's incorrect.

Technically nothing is incorrect. Auto decoding isn't incorrect. If that's how you view things in coding, as black and white, you can make that same argument against virtually everything. Surprises lead to bugs. Surprises that differ from how the rest of the language operates are even bigger surprises. Those kind of surprises can take hours to try to figure out what is going wrong. If you have an ambiguous call you get an error. The compiler doesn't choose one based on which one was defined first.

>> Rationale like your's is why the bug reports like this one remain open for 9+ years and it never gets fixed. It's not a bug it's a feature! Therefore any change is an enhancement and requires a DIP.
>
> There's this other language called Java that you may have heard of, that does things the exact same way, and the many millions of programmers that use that language seem to have no issue with this behaviour. I've already agreed that it would be worth having a way to write a different implementation for different interfaces with the same method, but that is the very *definition* of an enhancement.

Java isn't exactly the best language to look at. It's usually people's first language and then they just stick with it cause it's what they know. If you want to look at Java as an example for why something should be the way it is. Java doesn't have operator overloading. Anyways an easy counter example is that C# allows you to override the functions separately.

You can call it whatever you want. It doesn't change the fact this will just stay the way it is for another 9 years because people would rather sweep it under the rug due to ambiguity than fix it. Sure it's an edge case, but there's so many places in D where edges like this have questionable implementations, they start to add up.