10

Consider the following generic method:

public T2 Frob<T1, T2>(T1 item)
        where T1 : class, T2
        => item as T2;

The compiler will refuse to compile this code; The type parameter 'T2' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

Ok, this is easily solvable simply doing:

public T2 Frob<T1, T2>(T1 item)
        where T1 : class, T2
        where T2 : class
        => item as T2;

But isn't this redundant? Is there any possible T2 that is not a class considering the constraints already in place for T1?

My question is not why this "inference" wasn't implemented in the compiler, the reason could simply be "no one thought about it" and thats OK. I'm more interested in knowing if my reasoning is correct in that T2 is effectively and in all cases constrained to class in the first example even if its not explicitly enforced.

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • Why do you think the constraints for `T1` do also apply for `T2`? They have nothing in common, in particular whilst `T1` *derives* from `T2`, `T2` doesn´t know *anything* of `T1`. – MakePeaceGreatAgain Feb 13 '17 at 16:12
  • Sure, but `T2` itself isn´t constrained to anything, it could be even a `struct`. – MakePeaceGreatAgain Feb 13 '17 at 16:13
  • 1
    @HimBromBeere give me one example of a reference class deriving from a value type, because that is precisely what must happen with the constraints in place for `T1`. – InBetween Feb 13 '17 at 16:14
  • 1
    @HimBromBeere I think what OP means is that `T2` _cannot be a value type_ because `T1` cannot be derived from a value type. So it necessarily has to be a reference type. – René Vogt Feb 13 '17 at 16:15
  • Ah, okay, I see. Than I guess your reasoning is correct, however it is not implemented because of the allready mentioned fact. – MakePeaceGreatAgain Feb 13 '17 at 16:16
  • @RenéVogt where is it derivying? – MistyK Feb 13 '17 at 16:18
  • 4
    Personally I find these questions "Primarily opinion based" but questions about "Why did the C# designers implement X in the compiler" have been answered before so... what do I know. – Jamiec Feb 13 '17 at 16:18
  • My two cents here is that it's just an use case that's not currently implemented in generics. – Matías Fidemraizer Feb 13 '17 at 16:22
  • I mean, infering that "T1 is class and derives T2, thus T2 is a reference type too" – Matías Fidemraizer Feb 13 '17 at 16:23
  • 1
    @Jamiec If you read my question, I'm not asking *why* the compiler needs a redundant constraint. I'm asking if it *is* redundant or if there is some very strange corner case where it wouldn't be so. I can't think of any but I'd like to be 100% sure. – InBetween Feb 13 '17 at 16:25
  • 1
    Although this question is nice and shows research-affords I can´t see any way answering it except simply saying: yes, your reasoning is correct, however the behaviour you want assumes reverse constraining which isn´t implemented. – MakePeaceGreatAgain Feb 13 '17 at 16:26
  • 3
    One way or another, you're asking why a human being implemented it that way, or whether said human made an oversight. That's a question of motivation, and the only person who could answer it is the human who implemented it. – Jamiec Feb 13 '17 at 16:28
  • 1
    @HimBromBeere: Well, that's a good answer for a good question, isn't it? – O. R. Mapper Feb 13 '17 at 16:38

1 Answers1

4

My interpretation of this, given the C# 5.0 specs say at 7.10.11, The as operator:

In an operation of the form E as T, E must be an expression and T must be a reference type, a type parameter known to be a reference type, or a nullable type.

The compiler at that point only considers T2 in this block:

public T2 Frob<T1, T2>(T1 item)
        where T1 : class, T2
        => item as T2;

And it sees that T2 itself is not constrained. Sure, it could deduct that in this case T1 is expected to be a reference type and inherit T2, therefore that T2 itself should also be a reference type, but I'm sure there are reasons for not doing that.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 3
    Actually there probably *aren't* reasons for doing it other than what Eric Lippert notes in this answer: http://stackoverflow.com/a/1843557. TL;DR: "Features take time to implement." – aquinas Feb 13 '17 at 16:48