digitalmars.D.learn - Is this meant to be possible?
- ted (63/63) Feb 17 2014 I've been using D (at a primitive level) for a while now at work (a larg...
- Adam D. Ruppe (24/28) Feb 17 2014 This will cause the linker problem because templates cannot be
- ted (5/41) Feb 17 2014 Fantastic !! (thanks !)
- Adam D. Ruppe (4/8) Feb 19 2014 Yeah, that's good as long as you have a no-arg constructor on the
I've been using D (at a primitive level) for a while now at work (a large
test-harness that exercises our main code. The harness launches and monitors
multiple processes with multiple threads and performs actions on those
processes to ensure correct behaviour).
I am wanting to stretch my 'D' wings. I'm having some problems with trying
to do the following (reduced case) - and I'm wanting to know if D will even
(ever) allow it. Main reason is that I'm porting 'Ash' - a component/entity
system written in actionscript, which uses this type of construct. The key
issue is that if the line in main() is uncommented - a linker error occurs.
Clearly, there is a 'visibility' issue of 'provider' regarding 'TestClass'.
However, even if I add 'import main:TestClass' into module 'provider' - (and
introduce a compile-time circularity that I absolutely do not want) - it
still causes the link error - I guess the necessary information is lost
through the IProvider interface.
-------------------------------------
module IProvider;
public interface IProvider
{
string providedType();
T createInstance(T)();
}
-------------------------------------
module provider;
import IProvider;
public class Provider(T): IProvider
{
string providedType() { return T.classinfo.stringof;}
public T createInstance(T)() { return new T; }
}
-------------------------------------
module manager;
import provider;
import IProvider;
public class Manager
{
private { IProvider[ClassInfo] mProviders; }
public void add(T)() { mProviders[T.classinfo] = new Provider!T(); }
public IProvider get(T)() {
if ( T.classinfo in mProviders )
return mProviders[ T.classinfo ];
else
return null;
}
}
-------------------------------------
import manager;
import IProvider;
import std.stdio;
void main()
{
auto mgr = new Manager();
mgr.add!TestClass();
IProvider provider = mgr.get!TestClass();
writeln("managed type: ", provider.providedType);
//auto tmp = provider.createInstance!TestClass();
// Linker error if above line is uncommented
}
class TestClass
{
public int value;
}
-------------------------------------
Feb 17 2014
On Tuesday, 18 February 2014 at 00:31:22 UTC, ted wrote:
public interface IProvider
{
string providedType();
T createInstance(T)();
This will cause the linker problem because templates cannot be
virtual. This is declaring a final method in the interface that
is never implemented.
The reason they can't be virtual is that an interface consists of
an array of function pointers. Since templates might form
multiple functions based on their compile-time arguments, the
compiler can't know how many slots to reserve in that array for
it.
What you can do is something like this:
interface IProvider {
// this is a final method with an implementation right here
T createInstance(T)() {
auto i = cast(T) createDynamicInstance(typeid(T));
if(i is null) throw new Exception("Couldn't create " ~
T.stringof);
return i;
}
string providedType(); // virtual function
Object createDynamicInstance(ClassInfo type); // virtual
}
Then in the class, implement createDynamicInstance based on the
classinfo instead of the template. Your other code for add and
get should continue to work.
Feb 17 2014
Fantastic !! (thanks !)
so is:
createDynamicInstance(ClassInfo type) { return type.create(); }
the correct implementation ?? - it certainly seems to work...
Adam D. Ruppe wrote:
On Tuesday, 18 February 2014 at 00:31:22 UTC, ted wrote:
public interface IProvider
{
string providedType();
T createInstance(T)();
This will cause the linker problem because templates cannot be
virtual. This is declaring a final method in the interface that
is never implemented.
The reason they can't be virtual is that an interface consists of
an array of function pointers. Since templates might form
multiple functions based on their compile-time arguments, the
compiler can't know how many slots to reserve in that array for
it.
What you can do is something like this:
interface IProvider {
// this is a final method with an implementation right here
T createInstance(T)() {
auto i = cast(T) createDynamicInstance(typeid(T));
if(i is null) throw new Exception("Couldn't create " ~
T.stringof);
return i;
}
string providedType(); // virtual function
Object createDynamicInstance(ClassInfo type); // virtual
}
Then in the class, implement createDynamicInstance based on the
classinfo instead of the template. Your other code for add and
get should continue to work.
Feb 17 2014
On Tuesday, 18 February 2014 at 00:59:24 UTC, ted wrote:
so is:
createDynamicInstance(ClassInfo type) { return
type.create(); }
the correct implementation ?? - it certainly seems to work...
Yeah, that's good as long as you have a no-arg constructor on the
class. (the create function never passes arguments to the
constructor)
Feb 19 2014








"Adam D. Ruppe" <destructionator gmail.com>