www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Question about template argument matching with alias this

reply Johannes Loher <johannes.loher fg4f.de> writes:
I have a question about template argument matching in combination 
with implicit conversion and alias this. Consider the following 
code:


interface SomeInterface
{
}

class SomeClass : SomeInterface
{
}

struct SomeStruct
{
     SomeClass someClass;
     alias someClass this;
}

template isSuperType(T, S : T)
{
     enum isSuperType = is(SomeStruct : SomeInterface);
}

void main()
{
     static assert(is(SomeStruct : SomeInterface));
     static assert(isSuperType!(SomeInterface, SomeStruct)); // 
why does the template not match?
}


The question is, why does the template declaration not match? 
Thanks for your help!
Jul 29 2018
parent reply Alex <sascha.orlov gmail.com> writes:
On Sunday, 29 July 2018 at 16:43:08 UTC, Johannes Loher wrote:
 I have a question about template argument matching in 
 combination with implicit conversion and alias this. Consider 
 the following code:


 interface SomeInterface
 {
 }

 class SomeClass : SomeInterface
 {
 }

 struct SomeStruct
 {
     SomeClass someClass;
     alias someClass this;
 }

 template isSuperType(T, S : T)
 {
     enum isSuperType = is(SomeStruct : SomeInterface);
 }

 void main()
 {
     static assert(is(SomeStruct : SomeInterface));
     static assert(isSuperType!(SomeInterface, SomeStruct)); // 
 why does the template not match?
 }


 The question is, why does the template declaration not match? 
 Thanks for your help!
Do you mean something like this? ´´´ interface SomeInterface {} class SomeClass : SomeInterface {} struct SomeStruct { SomeClass someClass; alias someClass this; } template isSuperType(T, S) if(is(S : T)) { enum isSuperType = is(S : T); } static assert(is(SomeStruct : SomeInterface)); static assert(isSuperType!(SomeInterface, SomeStruct)); void main(){} ´´´
Jul 29 2018
parent reply Johannes Loher <johannes.loher fg4f.de> writes:
On Sunday, 29 July 2018 at 20:51:45 UTC, Alex wrote:
 Do you mean something like this?
 [...]
Yeah, I know that it possible to implement the template like this, but that is not the point here. I would like to know why it does not work the way I described it. To me it seems very strange, that `S : T` has different semantics in `is` expressions and as template parameters. My actual problem is the following: I would like to use the dependency injection framework poodinis [1] in conjuction with the mocking capabilities from unit-threaded [2]. My code would look something like the following: ``` import poodinis : DependencyContainer; import unit_threaded.mock : mock; interface SomeInterface { } unittest { auto myMock = mock!SomeInterface; alias MockedType = typeof(myMock) auto container = new shared DependencyContainer; container.register!(SomeInterface, MockedType)().existingInstance(myMock); /* ... */ } ``` The problem with this is that register has the signature described above, i.e. register(T, S : T)() and that the mock template from unit-threaded is actually implemented by a struct which is "alias this"ed (how do you call that...? :D) to a class which is derived from the mocked interface. This means I run exactly into the problem I described in the first post. Now I could ask the author of poodinis to remove the restriction on the template parameters for register, but it actually perfectly makes sense to have that restriction, because we are registering a concrete type as an abstract type. I also had a quick look at the implementation of mock, which seems to be quite complicated already. So I fear that changing this implementation to using a derived class directly is unlikely to happen. So I am back to my question: Why do we have this strange behavior? All compiler version on run.dlang.io behave like that, so I suppose there is some reason for this...? [0] https://github.com/mbierlee/poodinis [1] https://github.com/atilaneves/unit-threaded
Jul 29 2018
parent Alex <sascha.orlov gmail.com> writes:
On Sunday, 29 July 2018 at 23:03:27 UTC, Johannes Loher wrote:
 Yeah, I know that it possible to implement the template like 
 this, but that is not the point here. I would like to know why 
 it does not work the way I described it. To me it seems very 
 strange, that `S : T` has different semantics in `is` 
 expressions and as template parameters.
Yes... I see your point now. It is like "is" itself adds some semantics to the colon operator. So, while colon specifies, that only derivatives are matched, "is" matches all things, where the interface can be extracted... I think, this is intended: https://dlang.org/spec/template.html#argument_deduction p. 5 and https://dlang.org/spec/expression.html#is_expression p. 2 But... maybe some native D speaker could comment on this...
 Now I could ask the author of poodinis to remove the 
 restriction on the template parameters for register, but it 
 actually perfectly makes sense to have that restriction, 
 because we are registering a concrete type as an abstract type.
I would say, for practical reasons not to remove the restriction, but to formulate it in a more abstract way. This seems to be with ´if(is(S : T))´ in this case... As otherwise the restriction is to use classes only... (?)
 So I am back to my question: Why do we have this strange 
 behavior? All compiler version on run.dlang.io behave like 
 that, so I suppose there is some reason for this...?
Jul 30 2018