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