In the code:
Interface ISelf(Of Out TMe)
End Interface
Class SomeBase
Implements ISelf(Of SomeBase)
End Class
Class SomeDerived
Inherits SomeBase
Implements ISelf(Of SomeDerived)
End Class
Module ISelfTester
Sub TestISelf()
Dim z7 As New SomeDerived
Dim z8 As ISelf(Of SomeDerived)
Dim z9 As ISelf(Of ISelf(Of SomeDerived))
z8 = z7
z9 = z8
z9 = z7 ' Why is this illegal?
End Sub
End Module
The assignment directly from Z7 to Z9 yields the message "Error 13 Option Strict On does not allow implicit conversions from 'wokka.SomeDerived' to 'wokka.ISelf(Of wokka.ISelf(Of wokka.SomeDerived))' because the conversion is ambiguous." How is that assignment any more ambiguous than the one from Z7 to Z8, or Z8 to Z9? So far as I can tell, all three assignments must be representation-preserving conversions, meaning that all three must simply store a reference to the same object as Z7.
I could understand that if I were trying to assign an instance of SomeDerived
to a reference of type ISelf(Of ISelf(Of SomeBase))
, attempting to access a member of that interface could yield the implementation from either SomeBase
or SomeDerived
; if the member was a method with return type TMe
, I could understand that such ambiguity could cause compilation to fail (since the compiler wouldn't know what the return type would be). I'm puzzled, though, as to why merely trying to assign a reference fails because of "ambiguity", given that the assignment can't possibly be interpreted as anything other than a direct store of a reference to a reference-type variable?
BTW, the intended usage would be for ISelf(Of T)
to contain a read-only property Self
of type T
, for which the expected implementation would be Return This
[a representation-preserving conversion in every case; I suppose I should have added a class constraint to TMe
, but it doesn't affect the original problem]. If has a variety of classes which one is interested in implement ISelf(Of theirOwnTypes)
, it should be possible to leverage the covariance of ISelf
to facilitate some things that would otherwise be difficult [e.g. if each class one is interested in that implements IMoe
, ILarry
, and/or ICurly
, etc. also implements the corresponding classes ISelfAndMoe(Of ItsOwnType)
, ISelfAndLarry(Of ItsOwnType), and/or ISelfAndCurly(Of ItsOwnType), etc. then one can accept a parameter type which is known to implement any combination of those interfaces e.g.
ISelfAndMoe(Of ISelfAndLarry(Of ICurly)) param. Given that declaration,
paramwould implement
IMoe, and
param.Selfwould implement
ILarry, and
param.Self.Selfwould implement
ICurly. Further, if the class implements the expected pattern, one could cast
paramto e.g.
ISelfAndCurly(Of IMoe), if one wanted to call a routine which needed those two interfaces but didn't need
ILarry` (such cast could fail if an implementation did something unexpected, but should succeed if the object's class follows the expected pattern).