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