Generically call a function on Variant's payload?

Nick Sabalausky (Abscissa) SeeWebsiteToContactMe at semitwist.com
Mon Aug 20 19:38:13 UTC 2018


On 08/19/2018 11:31 PM, Paul Backus wrote:
> 
> You are basically reinventing OOP here.
> 

Yes, I am. Deliberately, in fact. Class inheritance is my backup plan, 
though.

My use-case is actually very, very similar to std.digest:

There are various benefits to using a template-and-constraint based 
interface. But one notable downside is the inability to handle the 
situation where the actual type needed is only known at runtime. In 
std.digest, this dilemma is dealt with by duplicating the entire 
interface in BOTH template/constraint AND class-inheritance varieties.

Additionally, an important thing to note in the case of std.digest is 
that `isDigest!T` returns FALSE for types using the OOP version of the 
interface. I think there is (arguably) a certain merit in that:

The OOP interface obviously uses classes, whereas (in order to obtain 
the full potential benefits of a template-and-constraint approach) the 
template interface uses (and even requires) structs. Because of this, 
instances should be constructed differently ("T instance;" vs "T 
instance = new T();"). Thus, any generic code that wants to handle ANY 
digest type must be very careful to mind this distinction whenever 
creating new instances. Presumably, this may be why std.digest chose to 
NOT let OO digests satisfy the template-oriented isDigest.

And then std.digest also needs WrapperDigest, needed to convert a 
template-style digest to OO-style.

So...while std.digest succeeds at offering the best-of-both-worlds 
between template and OO approaches, it also creates a whole new mess via 
completely duplicated interfaces that aren't 100% compatible.

I want to see if I can do better.

So back to the root of the problem:

We have a bunch of types, including user-defined types we don't have 
advance knowledge of. And we need a type which can hold any of them at 
runtime.

AFAIK, there are two classic ways to do that: One is OOP, the other is 
an unbounded discriminated union (a variant). Unlike class-based 
inheritance, a variant CAN be implemented as a struct. So, at least in 
theory, a variant-based type could potentially be made which implements 
the *true* template-based interface, eliminating the need for duplicate 
APIs and the mess that entails.

There are a bunch of discriminated union types available for D, but the 
only one I'm aware of that *doesn't* require a finite-sized list of 
types known ahead-of-time is Phobos's Variant. The only problem is 
calling a function on a type not already known ahead-of-time. Maybe 
that's unsolvable? If so, then I'll fallback to the std.digest approach. 
But I'd prefer to avoid that, if possible.


More information about the Digitalmars-d-learn mailing list