C++ 20's concepts are typeclasses and make object-based polymorphism obsolete - shockingly!

Perhaps, but it does satisfy the definition, if you go through each point:

  • ‘messaging’ — as others have pointed out, send is very similar if not identical to Smalltalk-style messaging
  • ‘local retention and protection and hiding of state-process’ — state is encapsulated in the effect handlers, and is inaccessible to the computation beyond the allowed messages
  • ‘extreme late-binding’ — OK, perhaps this is slightly more of a stretch, but after all the whole point of effects is that you can run them with different handlers

Anyway, my point wasn’t really about Haskell specifically… I was mostly trying to explain that ‘OOP’ is not necessarily synonymous with how C++ does it.

2 Likes

I’d say effect interpreters are as late-bindings as you can get!

This is the most enlightening explanation of object oriented style that I have seen so far. All these «late binding», «dynamic dispatch» words are nothing but buzz for me — I guess because no one ever told me what «binding» and «dispatch» are to begin with.

Let us check if I understand you right. For example say we have this code (in informal language):

class A
{
  void m₀ ( ) {m₁ ( );}
  void m₁ ( ) {print ("A");}
}

class B extends A
{
  void m₁ ( ) {print ("B");}
}

b = new B ( );
b.m₀;

— This should print B, even though we are running code defined as part of class A and the code printing B did not exist when the class A was defined.

Is this what is called «dynamic dispatch» and «late binding» in other sources?

I still cannot tell why this feature is so awesome that it warrants whole languages to be written for it. Maybe it is nice to have sometimes, but why such hype?

1 Like

No, that’s not quite right. The more compelling example is

f (A a) = a.m₀;
b = new B ( );
f b; // prints "B"

Why is this feature considered so awesome? I think it’s because when GUI programming was taking off we needed a convenient way of overriding some but not all behavior of widgets provided by GUI libraries.

1 Like

And to clarify what the difference is, f is defined only with knowledge of A yet a consumer can override its behavior by deriving a subclass B from A.

Another huge feature of common OOP language is that you can check if some value A a is also of type B, which allows you to call methods for type B for a. This allows calling pre-defined functionality with different data, making the program more flexible.

Hrm:

…is that really the case?

This one is called “dynamic cast”, but I’ve always considered it a violation of OOP - the whole point of OOP (or at least of dynamic dispatch) is that the caller doesn’t care what the actual type of the object is, but if you dynamic-cast it to a more specific type, then that means you do care.
Or, put differently: dynamic casting is a way of moving the dispatch from the callee and its place in the object hierarchy to the caller - you’re explicitly saying “if this fruit is an apple, then treat it as an apple”, whereas the object-oriented way would be to say “I don’t care whether this fruit is an apple, I will just treat it as a fruit, and then the fruit can decide for itself whether it is an apple and what that means”.

It is, however, considered a necessary evil, because staying true to pure OOP dispatch isn’t always the best way to model the situation at hand.

3 Likes