DLang - Template Constraints - the type must implement the interface
I am trying to convert the following C # code to D, however I cannot figure out how to get the template constraints to work.
C # implementation
public interface IComponent
{
}
public class Container
{
public T CreateComponent<T>() where T: IComponent, new()
{
// Trivial initialisation for example
var t = new T();
return t;
}
}
D Implement
public interface Component
{
}
public class Container
{
public T createComponent(T)()
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
How can I re-create the "where T: IComponent" constraint?
I've tried various combinations of expressions, typeof, etc., but can't find anything that works.
source to share
Well, if everything you are trying to do requires T
an interface to be implemented IComponent
, then it is(T : IComponent)
will check what is T
implicitly convertible to IComponent
(this is the case when IComponent
is the base class T
or the interface that it implements). So you end up with something like
public class Container
{
public T createComponent(T)()
if(is(T : IComponent))
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
Now, technically, other things might be the same if alias this
used to define an implicit conversion, which is unlikely to be common, but if you're more paranoid about it, you can make the constraint also check what T
is a class - is(T == class)
.
public class Container
{
public T createComponent(T)()
if(is(T == class) && is(T : IComponent))
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
Then it T
should be a class and it should implicitly convert to IComponent
. However, it is still technically possible that there T
would be a class that does not implement IComponent
, but defines alias this
which one is converted to IComponent
(for a T
struct that does this). So it's not ideal, but I don't know how to provide an implicit conversion via inheritance instead alias this
. So, unfortunately, I don't know how to absolutely guarantee that T
is the class that implements IComponent
. The most important thing I know how to do is make sure that it is implicitly converted to "IComponent", which almost always means it implements it.
However, the reality is that, in the vast majority of cases, it's just a is(T : IComponent)
lot of checking , and depending on how your code is written, it might even work with a type that is implicitly convertible to, IComponent
but it really isn't IComponent
. So the fact that alias this
throwing a wrench in the works may not actually be a problem. However, generally speaking, this alias this
is a general code bend and why most general codes should not check for implicit conversions. Too easy for type to implicitly convert viaalias this
, but not actually converting to a function, in which case it either won't compile or it might have strange behavior if it supports the same operations as the target type but those operations do not have the same results as if the original type were actually converted to target type. So, if you really want implicit conversions in the template code, you must force the implicit conversion by assigning the argument to the target type. But since you want to test the interface, not implicit conversions in general, what you probably want is a test that verifies this, avoiding implicit conversions throughalias this
... Unfortunately, the only way I know to check at compile time whether one type is derived from another or implements a particular interface is to check if it is implicitly converting to that base class or interface.
But maybe there is some kind of funny voodoo with features that can actually do it. If so, we should probably add something to std.traits, which will do it for you, and if not, maybe we should find a way to add it, as it alias this
can definitely be annoying if you don't want it. But fortunately, this is not a problem that occurs in most code, and unless you are writing a public API, you only need to worry about it if you declare types with alias this
. If you don't, then it really doesn't matter.
source to share
In typical form, I found the response points after requesting here http://ddili.org/ders/d.en/is_expr.html
public T addComponent(T)()
if (is(T: Component))
source to share