class template conflict

Neia Neutuladh neia at ikeran.org
Tue Dec 25 20:12:59 UTC 2018


On Tue, 25 Dec 2018 18:34:04 +0000, bauss wrote:
> I think there is a bigger problem at stake here in terms of software
> architecture.
> 
> What's the point needed for them to have the same identifier?

A probably abstract base class with only one child class. Normally you 
have "Foo" and "FooImpl", or "IFoo" and "Foo", but that's ugly.

This was the primary example that Michelle Long gave. I'd expect that a 
fair portion of people people who have used C# encountered this kind of 
situtaion. Like this sort of thing works in C#:

    class Foo {}
    class Foo<T> : Foo {}
    class Foo<T1, T2> : Foo {}

You can do this in C# because each of these are *classes*, and some just 
happen to have type parameters. In D, you'd have one class and two 
templates, and you can't overload two symbols of different kinds, so you 
have to write it as:

    class Foo() {}
    class Foo(T): Foo!() {}
    class Foo(T, U): Foo!() {}

In Java, for legacy reasons, this pattern is baked into the language; 
Foo<T> always has another class, Foo, that it implicitly casts to and 
from. Some people take advantage of that.

Most people who do both metaprogramming and OOP in D and have been doing 
that for a nontrivial amount of time probably encountered this exact same 
thing in D. I encountered it the first time before D2 was a thing.

> Clearly the two classes will have two different functions and should be
> named accordingly.

They will have different implementations and may have different 
interfaces. The proposed use case is inheritance, so X!10's public 
interface will be a superset of X's (and likely identical).

To give a slightly less contrived example, let's say you want to have some 
functions available to a scripting language. (I'm doing something like 
this in a side project for a CLI spreadsheet program.) Each function has a 
display name, help text, argument validation, and the function body.

If I had done this in an OOP style (and I might end up reworking it to look 
more like this), I'd have something like:

interface Function
{
  string helpText();
  string name();
  Nullable!Error validateParameters(Val[] parameters);
  Val execute(Val[] parameters);
}

And then I'd have a convenience mechanism to produce a conforming class 
from a function with UDAs:

class FunctionImpl(alias fn) : Function
{
override:
  string helpText() { return getUDAs!(fn, Help)[0].text; }
  string name() { return __traits(identifier, fn); }
  // etc
}

It would be slightly nicer to just have "Function" everywhere instead of 
both Function and FunctionImpl. Not enough to justify the complexity of 
the symbol lookup rules required. Not enough to make `class Foo(T)` mean 
something different from `template Foo(T) class Foo`. But it *would* be 
slightly nicer, and it would make things slightly more straightforward for 
people coming from C#.


More information about the Digitalmars-d-learn mailing list