Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does vb.net reject assignment to nested covariant interface as "ambiguous"

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 implementIMoe, andparam.Selfwould implementILarry, andparam.Self.Selfwould implementICurly. Further, if the class implements the expected pattern, one could castparamto e.g.ISelfAndCurly(Of IMoe), if one wanted to call a routine which needed those two interfaces but didn't needILarry` (such cast could fail if an implementation did something unexpected, but should succeed if the object's class follows the expected pattern).

like image 446
supercat Avatar asked Oct 06 '22 17:10

supercat


1 Answers

Option Strict On tells the compiler to ignore a simple reference to reference implicit conversion. It's implicit because z9 is allowed to be a SomeBase(Of SomeBase(Of SomeDerived) and because SomeDerived can be substituted for SomeBase the compiler isn't sure which one you mean. But because you explicitly say in z8 that it's ISelf(of SomeDerived) there isn't any guesswork. I suspect if you changed z9 to ISelf(Of SomeDerived(Of SomeDerived) that ambiguity may go away.

As an opinion, however, this sort of nesting gets very confusing as it stacks on itself and can become a nightmare to maintain.

like image 99
Joel Etherton Avatar answered Oct 10 '22 02:10

Joel Etherton