by via Fabulous Adventures In Coding on 9/21/2009 4:36:00 PM
Here's a good question from StackOverflow:
If you have a method that takes an "X" then you have to pass an expression of type X or something convertible to X. Say, an expression of a type derived from X. But if you have a method that takes a "ref X", you have to pass a ref to a variable of type X, period. Why is that? Why not allow the type to vary, as we do with non-ref calls?
Let's suppose you have classes Animal, Mammal, Reptile, Giraffe, Turtle and Tiger, with the obvious subclassing relationships.
Now suppose you have a method void M(ref Mammal m). M can both read and write m. Can you pass a variable of type Animal to M? No. That would not be safe. That variable could contain a Turtle, but M will assume that it contains only Mammals. A Turtle is not a Mammal.
Conclusion 1: Ref parameters cannot be made "bigger". (There are more animals than mammals, so the variable is getting "bigger" because it can contain more things.)
Can you pass a variable of type Giraffe to M? No. M can write to m, and M might want to write a Tiger into m. Now you've put a Tiger into a variable which is actually of type Giraffe.
Conclusion 2: Ref parameters cannot be made "smaller".
Now consider N(out Mammal n).
Can you pass a variable of type Giraffe to N? No. As with our previous example, N can write to n, and N might want to write a Tiger.
Conclusion 3: Out parameters cannot be made "smaller".
Can you pass a variable of type Animal to N?
Hmm.
Well, why not? N cannot read from n, it can only write to it, right? You write a Tiger to a variable of type Animal and you're all set, right?
Wrong. The rule is not "N can only write to n". The rules are, briefly:
1) N has to write to n before N returns normally. (If N throws, all bets are off.)2) N has to write something to n before it reads something from n.
That permits this sequence of events:
That scenario -- using multithreading to write into a variable that has been aliased -- is awful and you should never do it, but it is possible.
UPDATE: Commenter Pavel Minaev correctly notes that there is no need for multithreading to cause mayhem. We could replace that fourth step with
Regardless of how the variable's contents might get altered, clearly we want to make the type system violation illegal.
Conclusion 4: Out parameters cannot be made "larger".
There is another argument which supports this conclusion: "out" and "ref" are actually exactly the same behind the scenes. The CLR only supports "ref"; "out" is just "ref" where the compiler enforces slightly different rules regarding when the variable in question is known to have been definitely assigned. That's why it is illegal to make method overloads that differ solely in out/ref-ness; the CLR cannot tell them apart! Therefore the rules for type safety for out have to be the same as for ref.
Final conclusion: Neither ref nor out parameters may vary in type at the call site. To do otherwise is to break verifiable type safety.
Original Post: Why do ref and out parameters not allow type variation?
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.