August 25, 2014
On Monday, 25 August 2014 at 01:10:32 UTC, Aerolite wrote:
> -- No syntax modification (unless you want the feature to be
> optional)

If this ever gets into the core language, it absolutely must be optional! Think of the implications of having this as the default and only behavior:

 * Every overloaded function will have to do a runtime typecheck - this not only causes a usually unnecessary overhead but also has a negative impact on branch prediction.

 * No way to reuse the overload that accepts an object of the parent class inside the implementation of the overload that accepts an object of the child class.

 * What if you have multiple overloads that happen to be templated? Now the compiler will have to instantiate them all!



Anyways, I don't think you get just how strong this language's tendency to push features to the library is, so I'd like to point you to this post by the language's creator:

http://forum.dlang.org/thread/lt00a9$2uoe$1@digitalmars.com#post-lt00a9:242uoe:241:40digitalmars.com
August 25, 2014
On Monday, 25 August 2014 at 01:34:14 UTC, Idan Arye wrote:
> On Monday, 25 August 2014 at 01:10:32 UTC, Aerolite wrote:
>> -- No syntax modification (unless you want the feature to be
>> optional)
>
> If this ever gets into the core language, it absolutely must be optional! Think of the implications of having this as the default and only behavior:
>
>  * Every overloaded function will have to do a runtime typecheck - this not only causes a usually unnecessary overhead but also has a negative impact on branch prediction.

Well, you'd only have to resolve *class* parameters (since
obviously literals and structs don't support inheritance). My
brain is a little foggy at the moment due to this nice flu I
have, but do we even need to do this at run-time? It's not like
we can do a Java and use run-time reflection to create new class
instances. The closest thing we have to that is Object.factory,
but that's all compile-time built and type-safe as far as I'm
aware? Or am I being silly?

>  * No way to reuse the overload that accepts an object of the parent class inside the implementation of the overload that accepts an object of the child class.

Ok, yep, I didn't consider this. Fair point. But surely an
attribute such as @nomulti could prevent this problem? Admittedly
though, given this problem, the scale of potential breaking
changes would necessitate the opposite - an @multimethod
attribute, for instance (much like you suggested in your earlier
reply).

Clojure, it seems[1], explicitly denotes multimethods (with
defmulti), so it seems as though an @multimethod might be the way
to go.

>  * What if you have multiple overloads that happen to be templated? Now the compiler will have to instantiate them all!

Hard to say, although surely there could be some examination of
what is and is not necessary to instantiate. This is again making
the implementation a tad more complicated, though. That said, if
something like @multimethod existed, it would assist in this
matter.

> Anyways, I don't think you get just how strong this language's tendency to push features to the library is, so I'd like to point you to this post by the language's creator:
>
> http://forum.dlang.org/thread/lt00a9$2uoe$1@digitalmars.com#post-lt00a9:242uoe:241:40digitalmars.com

Heh. Well, that's Walter for you! :P But I definitely understand
the push towards the library. I just feel that handling method
dispatch, even in compile-time template code, is not something
that we should really be writing ourselves. It's like trying to
do virtual method calls in C!

  [1]:
http://clojure.org/multimethods
August 25, 2014
On Mon, 25 Aug 2014 01:14:19 +0000
Aerolite via Digitalmars-d-learn <digitalmars-d-learn@puremagic.com>
wrote:

> I just can't help but think that really, such a feature should be at the language level.
this is the first topic about multiple-dispatch in at least... eh... 6 months (maybe more). chances that it will be included in compiler are less than zero.


August 25, 2014
On Monday, 25 August 2014 at 02:04:43 UTC, Aerolite wrote:
> On Monday, 25 August 2014 at 01:34:14 UTC, Idan Arye wrote:
>> On Monday, 25 August 2014 at 01:10:32 UTC, Aerolite wrote:
>>> -- No syntax modification (unless you want the feature to be
>>> optional)
>>
>> If this ever gets into the core language, it absolutely must be optional! Think of the implications of having this as the default and only behavior:
>>
>> * Every overloaded function will have to do a runtime typecheck - this not only causes a usually unnecessary overhead but also has a negative impact on branch prediction.
>
> Well, you'd only have to resolve *class* parameters (since
> obviously literals and structs don't support inheritance). My
> brain is a little foggy at the moment due to this nice flu I
> have, but do we even need to do this at run-time? It's not like
> we can do a Java and use run-time reflection to create new class
> instances. The closest thing we have to that is Object.factory,
> but that's all compile-time built and type-safe as far as I'm
> aware? Or am I being silly?

If multi-dispatching is done at compile-time, it can't rely on the object's runtime type - only on the static type of the reference that holds it. This is no different than regular function overloading that we already have.

>> * What if you have multiple overloads that happen to be templated? Now the compiler will have to instantiate them all!
>
> Hard to say, although surely there could be some examination of
> what is and is not necessary to instantiate. This is again making
> the implementation a tad more complicated, though. That said, if
> something like @multimethod existed, it would assist in this
> matter.

Are you suggesting the compiler will try to resolve the polymorphism at compile-time, looking at all possible paths that lead to a function call to check all possible runtime values it's object arguments can get?

>> Anyways, I don't think you get just how strong this language's tendency to push features to the library is, so I'd like to point you to this post by the language's creator:
>>
>> http://forum.dlang.org/thread/lt00a9$2uoe$1@digitalmars.com#post-lt00a9:242uoe:241:40digitalmars.com
>
> Heh. Well, that's Walter for you! :P But I definitely understand
> the push towards the library. I just feel that handling method
> dispatch, even in compile-time template code, is not something
> that we should really be writing ourselves. It's like trying to
> do virtual method calls in C!

Virtual methods in C can be done with GObject - though the syntax is awkward. D is so much better than C when it comes to metaprogramming, that the syntax for multimethods wouldn't be awkward(unless you consider anything that's not burned to the core syntax awkward)
August 25, 2014
On Monday, 25 August 2014 at 07:36:22 UTC, Idan Arye wrote:
> Are you suggesting the compiler will try to resolve the polymorphism at compile-time, looking at all possible paths that lead to a function call to check all possible runtime values it's object arguments can get?

I've argued for whole program analysis before and this is another example where it would be useful :-). When you have figured out the worst-case use pattern you can either make one function virtual and then inline the others as a switch or you can create class-ids that can be hashed perfectly to an array of function pointers.

However, why do you want multiple dispatch? I cannot think of any application level use scenario where you have two class hierarchies that you have no control over. So I don't really see the value of multiple dispatch in a system level programming language. Perhaps if you want to use D for an application level DSL? What are the use scenarios you guys have experience with where multiple dispatch was indispensable?

Ola.
August 25, 2014
On Monday, 25 August 2014 at 07:36:22 UTC, Idan Arye wrote:
> If multi-dispatching is done at compile-time, it can't rely on the object's runtime type - only on the static type of the reference that holds it. This is no different than regular function overloading that we already have.

Well any library solution has to do this at compile-time... I
assume the implementation would be similar, albeit easier because
the compiler would have all the necessary information directly
accessible.

> Are you suggesting the compiler will try to resolve the polymorphism at compile-time, looking at all possible paths that lead to a function call to check all possible runtime values it's object arguments can get?

Is that not what would have to be done for a library solution in
this case, anyway?

> Virtual methods in C can be done with GObject - though the syntax is awkward. D is so much better than C when it comes to metaprogramming, that the syntax for multimethods wouldn't be awkward(unless you consider anything that's not burned to the core syntax awkward)

Of course, I understand this. What I'm saying is that while it's
possible to do virtual method calls in C, the very fact that it
had to be implemented so awkwardly meant that a library solution
was not ideal. Now in D, the syntax is infinitely better, given.
Templates and compile-time code-generation are all really good.
But as I said, we have a lot of template bloat issues already.
Running 3 foreach-loops at compile-time every time that
template-function gets instantiated doesn't seem scalable to
me... Having something like this in the compiler, which has all
the required information available directly, seems like it'd be
the most scalable solution.
August 25, 2014
On Monday, 25 August 2014 at 08:45:15 UTC, Ola Fosheim Grøstad
wrote:
> However, why do you want multiple dispatch? I cannot think of any application level use scenario where you have two class hierarchies that you have no control over. So I don't really see the value of multiple dispatch in a system level programming language. Perhaps if you want to use D for an application level DSL? What are the use scenarios you guys have experience with where multiple dispatch was indispensable?
>
> Ola.

Well there are a few go-to use-cases, the handling of collisions
between objects in a game-engine being the most well-known (which
requires Double-Dispatch). But it's basically anything that
requires the Visitor Pattern, plus extra.

At the end of the day, most (if not all) of the major software
patterns have come about and are used due to shortfalls in the
major languages. D, at least in my experience, tends to solve a
lot of these shortfalls, and given that design path, why
*wouldn't* we want Multiple Dispatch in the language?
August 25, 2014
On Monday, 25 August 2014 at 10:16:29 UTC, Aerolite wrote:
> Well there are a few go-to use-cases, the handling of collisions
> between objects in a game-engine being the most well-known (which
> requires Double-Dispatch).

I think a game engine is better off using a simple table or a more homogeneous engine based on properties rather than classes. You usually can assign a small integer to the relevant properties and use a 2D LUT.

> D, at least in my experience, tends to solve a
> lot of these shortfalls, and given that design path, why
> *wouldn't* we want Multiple Dispatch in the language?

I have never had a need for it, but maybe I would have used it if it was available.

I think, however, that it would fit better in Go which are going for a more "dynamic" implementation of interfaces without OOP.

I certainly see some value in detaching virtual functions from the record definition. I believe bitC might go in that direction as well.
August 25, 2014
On Monday, 25 August 2014 at 10:02:41 UTC, Aerolite wrote:
> On Monday, 25 August 2014 at 07:36:22 UTC, Idan Arye wrote:
>> If multi-dispatching is done at compile-time, it can't rely on the object's runtime type - only on the static type of the reference that holds it. This is no different than regular function overloading that we already have.
>
> Well any library solution has to do this at compile-time... I
> assume the implementation would be similar, albeit easier because
> the compiler would have all the necessary information directly
> accessible.

This CAN NOT BE DONE at compile-time, since the compiler doesn't know at compile time the exact subclass of the instance it'll get at runtime. To clarify: I'm not talking about the creation of the multi-method mechanism - which *can* be done at compile-time - I'm talking about invoking that mechanism to determine which overload to call, and this can only be done at runtime.

>> Are you suggesting the compiler will try to resolve the polymorphism at compile-time, looking at all possible paths that lead to a function call to check all possible runtime values it's object arguments can get?
>
> Is that not what would have to be done for a library solution in
> this case, anyway?

If you look back, you'll notice this argument(and the two before it) was not against multi-methods at the language level - it was about multi-methods by default. If they are optional, instantiating all the overloads will only happen when it's used, so it won't be that bad.

>> Virtual methods in C can be done with GObject - though the syntax is awkward. D is so much better than C when it comes to metaprogramming, that the syntax for multimethods wouldn't be awkward(unless you consider anything that's not burned to the core syntax awkward)
>
> Of course, I understand this. What I'm saying is that while it's
> possible to do virtual method calls in C, the very fact that it
> had to be implemented so awkwardly meant that a library solution
> was not ideal. Now in D, the syntax is infinitely better, given.
> Templates and compile-time code-generation are all really good.
> But as I said, we have a lot of template bloat issues already.
> Running 3 foreach-loops at compile-time every time that
> template-function gets instantiated doesn't seem scalable to
> me... Having something like this in the compiler, which has all
> the required information available directly, seems like it'd be
> the most scalable solution.

No one is trying to claim that a library implementation will be superior to a language-level solution in terms of speed, memory usage, binary size, compilation speed or syntax elegance. Language-level solutions can usually achieve better results in these regards. The problem is that they come with a price:

 * External tools needs to be modified to work with them.

 * Alternative implementations need to implement them(even though the frontend is shared, there can always be some complications(plus I think mutli-methods might need some backend modifications as well, thhoguh I'm no expert on that matter))

 * Risking regressions - changing the code will never be as orthogonal as changing the data it works on...

The point is that the usefulness of multi-methods, and the inconvenience of having as a library solution are not nearly big enough to pay that price.
August 25, 2014
On Monday, 25 August 2014 at 17:16:10 UTC, Idan Arye wrote:
>  * Alternative implementations need to implement them(even though the frontend is shared, there can always be some complications(plus I think mutli-methods might need some backend modifications as well, thhoguh I'm no expert on that matter))
>
>  * Risking regressions - changing the code will never be as orthogonal as changing the data it works on...
>
> The point is that the usefulness of multi-methods, and the inconvenience of having as a library solution are not nearly big enough to pay that price.

If we assume just double-dispatch over class-types and that you instantiate all functions first. Couldn't you then have this:

eat(virtual BaseBeing v, virtual BaseFood f,float amount){}
eat(virtual Human v, virtual Fruit f,float amount){]
eat(virtual Human v, virtual Stone f,float amount){}
eat(virtual Monster v, virtual Corpse f,float amount){}
eat(virtual Human v, virtual Corpse f,float amount){}

Then extend the typeinfo of classes in the first param with a minimal typeid and 2D table that lists all combinations that the "custom linker" can find based on the mangling?

Or maybe there are some hidden traps…