Why it is not possible to declare a method parameter as var type

I wonder why it is impossible to use a method parameter as var type like

private void myMethod(var myValue) { // do something } 
+4
source share
9 answers

You can use var for variables inside the method body. Also, the variable must be assigned during the declaration, and it must be unambiguously deduced from the expression on the right side.

In all other places, you must specify the type, even if the type can theoretically be inferred.

The reason is due to the way the compiler is designed. A simplified description is that it first parses everything except the method bodies, and then does a full analysis of the static types of each class, member, etc. He then uses this information to analyze the method bodies and, in particular, to infer the type of local variables declared as var . If var allowed anywhere, then this will require a significant change in the way the compiler works.

You can read Eric Lippert's article on this subject for more details:

+9
source

Because the compiler determines the actual type by looking at the right side of the job. For example, here it is defined as a string:

 var s = "hello"; 

Foo defined here:

 var foo = new Foo(); 

There is no "right side of destination" in the method arguments, so you cannot use var.

+7
source

Please see Juliet's answer for a better answer to this question.

Because it was too difficult to add complete type inference to C #. Other languages, such as Haskell and ML, can automatically infer the most common type without specifying it.

Other answers state that it is "impossible" for the compiler to infer the type var, but in fact it is possible in principle. For instance:

 abstract void anotherMethod(double z, double w); void myMethod<T>(T arg) { anotherMethod(arg, 2.0); // Now a compiler could in principle infer that arg must be of type double (but the actual C# compiler can't) } 

The parameters of the var method are basically the same as the general methods:

 void myMethod<T>(T arg) { .... } 

Unfortunately, you cannot just use the same syntax for both, but this is probably due to the fact that this C # type output was only added later.

In general, subtle changes in the syntax and semantics of a language can turn a "deterministic" type inference algorithm into an unsolvable one.

+7
source

See Eric Lippert 's publication on why var is not allowed in fields, which also explains why it doesn't work in method signatures:

Let me give you a brief simplification of the C # compiler. First, we run each source file and execute the "top-level only" syntax. That is, we identify each declaration such as a namespace, class, structure, enumeration, interface, and delegate at all levels of nesting. We analyze all field declarations, method declarations, etc. In fact, we parse everything except the bodies of the method; those we will skip and come back to them later.
[...]
if we have “var” fields, then the field type cannot be determined until the expression has been parsed, and this will happen after we already need to know the field type.

+7
source

ML, Haskell, Scala, F #, SML, and other languages ​​can easily determine the type from equivalent expressions in their own language, mainly because they were designed with the type in mind from the start. C # was not, its output type was used as a post-hoc solution to the problem of access to anonymous types.

I assume that the true Hindley-Milner type inference has never been implemented for C # because it is difficult to infer types in the language, so it depends on classes and inheritance. Let's say I have the following classes:

 class Base { public void Print() { ... } } class Derived1 : Base { } class Derived2 : Base { } 

And now I have this method:

 var create() { return new Derived1(); } 

What type of return is here? Is it Derived1 , or should it be Base ? If so, should it be object ?

Ok, now let's say that I have this method:

 void doStuff(var someBase) { someBase.Print(); } void Main() { doStuff(new Derived1()); doStuff(new Derived2()); // <-- type error or not? } 

The first call to doStuff(new Derived1()) supposedly leads to doStuff type doStuff(Derived1 someBase) . Suppose now that we derive a specific type instead of a generic type T

What about the second call, doStuff(new Derived1()) ? Is this a type error, or are we generalizing instead of doStuff<T>(T somebase) where T : Base ? What to do if we made the same call in a separate assembly without links - the type inference algorithm would have no idea whether to use a narrow type or a more genenarlized type. Thus, we get two signatures of different types based on whether the method calls from within the assembly or from another assembly.

You cannot generalize wider types based on the use of a function. Usually you need to rely on one particular type as soon as you know which particular type passes. Thus, in the above code example, if you have not explicitly switched to the base type, doStuff limited to accept Derived1 types, and the second call is a type error.

Now the trick here settles on the type. What is going on here:

 class Whatever { void Foo() { DoStuff(new Derived1()); } void Bar() { DoStuff(new Derived2()); } void DoStuff(var x) { ... } } 

What type of doStuff ? In this regard, we know, based on the foregoing, that one of the Foo or Bar methods contains a type error, but can you determine who has the error?

Cannot resolve type without changing C # semantics. In C #, the method declaration order does not affect compilation (or at least should not;)). Instead, you can say that the method declared first (in this case, the Foo method) determines the type, so Bar has an error.

This works, but also changes the semantics of C #: changes in the method order will change the compiled type of the method.

But let's say we went further:

 // Whatever.cs class Whatever { public void DoStuff(var x); } // Foo.cs class Foo { public Foo() { new Whatever().DoStuff(new Derived1()); } } // Bar.cs class Bar { public Bar() { new Whatever().DoStuff(new Derived2()); } } 

Now methods are called from different files. Which type? It is impossible to solve without imposing some rules on the compilation order: if Foo.cs compiles before Bar.cs, the type is determined by Foo.cs.

Although we can enforce such rules in C # to do work with the type of inference, it would radically change the semantics of the language.

Unlike ML, Haskell, F # and SML, output type inference is so good that they have these kinds of restrictions: you cannot call methods before they are declared, the first method call for the derived functions determines the type, the compilation order affects the type inference and etc.

+6
source

The keyword "var" is used in C # and VB.NET to deduce a type - you basically tell the C # compiler: "you figure out what a type is."

"var" is still strongly typed - you're just too lazy to write a type and let the compiler understand it - based on the data type of the right-hand side of the job.

Here, in the method parameter, the compiler cannot understand what you really mean. How? What type did you really mean? There is no way for the compiler to infer a type from a method definition, so it is not correct.

+1
source

Because C # type is type safe and strong . Anywhere in your program, the compiler always knows the type of argument you are using. The var keyword was entered only for variables like anonymous type.

+1
source

Check dynamic in C # 4

0
source

Type input is type inference, either in local expressions or in global / interprocedural. Therefore, we are not talking about the “absence of the right side”, because in compiler theory, calling a procedure is a form of the “right side”.

C # can do this if the compiler has done global type inference, but that is not the case.

You can use an “object” if you need a parameter that takes something, but then you need to deal with runtime conversion and potential exceptions yourself.

"var" in C # is not a run-time type binding, it is a compile-time function that ends with a very specific type, but C # type output is limited in scope.

0
source

Source: https://habr.com/ru/post/1305984/


All Articles