It's in fact the same.
It's in fact the same.
Obj f(Obj a, Obj b);
in C++, you pass in Obj's vtable twice, and the returned value includes a vtable.If you have
f :: Obj a => a -> a -> a
in Haskell, you pass in one dictionary. If you have f :: (Obj a, Obj b) => a -> b -> a
in Haskell, you pass in two dictionaries. If you have f :: (Obj a, Obj b, Obj c) => a -> b -> c
you pass in three dictionaries, and the caller gets to decide what the concrete type of c is, NOT the function implementation. data DynObj = forall c. Obj c => DynObj c
f :: (Obj a, Obj b) => a -> b -> DynObj
In this case, you pass in two dictionaries and the returned value has a vtable. This essentially is what C++ does.The advantage is that "interfaces" can be attached to objects non intrusively (and outside of that object declaration, which is a huge win for interoperability), the disadvantage is that pointers are larger and there is no easy way to cross cast between interfaces.
In c++ "fat pointers" (also sometimes known are virtual concepts) are often implemented manually, the most well known example is std::function. We are all waiting for compile time reflection to be able to implement virtual concepts generically (you can only approximate it up to a point currently).
(This is basically why Rust doesn't support multi-trait types (e.g. &dyn Debug + Clone)
trait Foo: Debug + Clone {}
Edit: No you can't, because `Clone` requires `Sized`, which means you can't make a trait object of `Foo`.https://play.rust-lang.org/?version=stable&mode=debug&editio...
Edit: Assuming we're talking about objects that can be grouped into some sort of 'classes'.
Perhaps gpderetta said it better: https://news.ycombinator.com/item?id=23537639