DIP 45 - approval discussion
Jakob Ovrum
jakobovrum at gmail.com
Tue Nov 12 15:05:46 PST 2013
On Tuesday, 12 November 2013 at 22:36:22 UTC, Timon Gehr wrote:
> - Every class in any imported module will need to show up in
> the generated code even if it is never used unless global
> static analysis is carried out on arguments to Object.factory.
>
> - If I know the fully qualified name of a class, there are
> better ways to instantiate this class than passing a string
> containing that name to Object.factory in order to call the
> default constructor.
>
> - The functionality provided by Object.factory is trivially
> replaced by a solution more specifically tailored to the
> problem at hand using compile-time reflection.
+ 1.
To test, I made a Factory template that works like this:
---
unittest
{
import std.traits : fullyQualifiedName;
interface I {}
class A : I {}
class B : I {}
alias f = Factory!(I, A, B);
static assert(is(f.Product == I));
I a = f.create(fullyQualifiedName!A);
assert(cast(A)a);
I b = f.create(fullyQualifiedName!B);
assert(cast(B)b);
}
---
Some notes:
* The first parameter, the Product parameter, which can be any
class or interface, is required because CommonType is always
Object when given a heterogeneous list of classes. I assume this
is because of the difficulty of choosing a common interface when
multiple interfaces are present.
* All subsequent parameters, the factory provider classes, are
of course checked that they actually implement the Product,
whether as a base class or an interface. Is a bit of a gotcha
because AliasThis has to be "worked around" in the checking code.
* Implementation uses a sorted array instead of an AA because
AAs can't be transferred from CT to RT yet.
* The array is immutable, so the same list is used for the same
Factory across threads (but I suppose that has no real
significance, just an observation).
* If the Product member is deemed unnecessary, it could just be
a function template instead of a template with two members
(Product and create).
Advantages over Object.factory:
* The opCall returns Product, not Object, so client code doesn't
need to cast in most circumstances.
* `fullyQualifiedName` is used in the example because it
internally uses `TypeInfo_Class.create`, which requires the full,
internal names of the A and B types, which of course, are nested
in a unittest. However, since the range of implementations are
known, it could be amended to statically figure out a less strict
naming scheme. In this case, just "A" and "B" could be made valid
without ambiguity. Object.factory cannot practically do this.
* Interestingly, since it knows all the constructors, it could
present an overload set of the constructors that all implementors
support, with some implementation effort!
* Lookup has the opportunity to be a lot faster than
Object.factory due to the smaller set of providers.
* The runtime list of providers does not contain types that
aren't part of the set (duh), hence no bloat.
The disadvantage is that all implementing types must be passed at
compile-time. That is the only advantage of Object.factory,
AFAICS. As it seems like a very niche need that everyone has to
pay for, I don't think Object.factory carries its weight.
More information about the Digitalmars-d
mailing list