What Are The Semantics Of Multiple Implicitly Typed Declarations? Part One

What Are The Semantics Of Multiple Implicitly Typed Declarations? Part One

  • Comments 21

In my earlier series on inferring a unique "best" type from a set of expressions I mentioned that one potential application of such an algorithm is in implicitly typed variables. This led to some good questions and concerns posted in the comments - questions and concerns which echo similar feedback we've been receiving from a variety of sources since we released the first technology preview of C# 3.0 last year.

I'd like to run a quick unscientific poll to see what your intuitions and expectations about implicitly typed variables with multiple declarations are. Please leave a comment describing what you think should happen here, and why you think that.

1: local variable declaration var x = 1, y = 2.0; has the same semantics as:
(a) double x = 1, y = 2.0;
(b) int x = 1; double y = 2.0;
(c) object x = 1, y = 2.0;
(d) this should be a compile-time error
(e) something else, please specify

2: local variable declaration var q = 0, r = (short)6; has the same semantics as:
(a) int q = 0; short r = 6;
(b) int q = 0, r = 6;
(c) short q = 0, r = 6;
(d) object q = 0, r = 6;
(e) this should be a compile-time error
(f) something else, please specify

Thanks! Next time I'll describe some of the pros and cons of each and what our current thinking is in this area.

  • Definitely 1b, 2a. The general rule I'm going with here is that

    var a=A, b=B;

    should be exactly equivalent to:

    var a=A;
    var b=B;

    In a sense this is exactly equivalent to the way that other multiple declarations work - if you replace "var" with any real type, this equivalence holds. So I think it passes the "intuitive" test a lot better than any of the other options.
  • I'd agree with 1b, 2a also. Though I come to that from interpreting what the coder was thinking of when declaring variables. If lacking type information then I'd presume that things are typed into the most restrictive logical data type given information about the initialisation value. Thus leaving the programmer to explicitly define alternative types, as per the syntax of question 2. I'd also agree that var a=B, b=B is equivalent to var a=A; var b=B.
  • 1e, 2e

    Ambiguity, as I've found, is the primary cause of subtle bugs in code. Given that it should be illegal to put yourself in to a position like that. Or, it should be a compile-time warning, though given that you can't get rid of the warning unless you change the type, it might as well be an error.

    "In a sense this is exactly equivalent to the way that other multiple declarations work - if you replace "var" with any real type, this equivalence holds. So I think it passes the "intuitive" test a lot better than any of the other options."

    Except under that logic you could put:

    int a = 2, b = "hello";

    I think intuitive tests have to pass both directions here. Since I can't translate:

    int a = 2;
    string b = "hello";

    into

    int a = 2, b = "hello";
    or
    string a = 2, b = "hello";

    I shouldn't, intuitively, be able to translate the var equivalents. Hence, it fails the bidirectional argument.
  • Given that I don't think you should EVER have been able to do this in C#.
      int x =0, y=1;
    to start with (it's just-plain ugly and lazy), I'll got for 1d, 2e.

    But I'm pedantic... if you absolutely must allow the syntax, then the priniciple of least surprise should yield the same behavior as C++ (e.g. all types on the same line share a type) which is option 1b and perhaps a warning that the 2.0 is being truncated... definately a compile time ERROR if it was B was being assigned 2.1 (or any other non-integral value).

    Likewise, 2 should be 2b... simply because in the absence of type information we should dump to int for q, then based on C++ rules r has the same type and is assigned a widened short 6.


  • I also agree with 1b, 2a. Multiple declarations on a single line is syntactic sugar for the equivalent set of declarations with the same declared type.
  • My answers (without looking at any other comments) would be:

    1 (b)
    2 (a)

    I think there should be no difference between:

    var x = 1, y = 2.0;

    and

    var x = 1;
    var y = 2.0;

    And similarly, no difference between:

    var q = 0, r = (short) 6;

    and

    var q = 0;
    var r = (short) 6;

    Applying the type inference rules: 0 -> int, 1 -> int, 2.0 -> double, (short) 6 -> short leads to my given answers. That said, I could definitely live with flagging both as compilers errors, so answer (d).
  • 1 = b and 2 = a, if only because this is what I'm used to from every other language I know of that uses type inference.
  • I'm going to be an oddball and say that it ought to be 1A and 2C.

    I think that under no circumstances should a single instance of the var keyword evaluate to more than one type (this is similar to what Marc Brooks said).

    In the case in which the developer explicitly specifies type information (via casting, etc.) on one of the variables, I believe that the compiler should try to apply this type to all of the declared variables on that line. If there are multiple casts to different types, this should be an error.

    And I definitely agree with the others that have specified that this kind of code should generate warnings at the very least.
  • 1b 2a

    Yeah it's a bit annoying at first glance, but I think it works the best.
  • 1a, 2b: We should be able to do x = y and y = x. A valid reason to use  multiple declarations (the only readon I can think of) is to be sure that we end up with two locals with the same type.
  • Definitely 1b, 2a.  Same reasons cited by Stuart and Douglas.

    Plus there's historical precedent in C, where it is possible to declare variables of different types on one line.
    char ch, *pch, **ppch, rgch[10], (*pfn)(void);

    Whether it was a good idea for C to allow this sort of thing is another question entirely. :-)
  • 1) b
    2) a
  • 1a, 2b

    I think it would be tedious to debug code where expressions are used to initialise the variables if multiple type can be initialised implicitly in a single statement.  In the interest of mainatiablility, I feel this should be flaged as an error / warning, or the largest data type would be used.  Having said that, it would be a problem if var x = 1, y = 2.0, z="abc"; has to be parsed and hence my answer applies if we are dealing with similar data type.
  • It seems that the choice comes down to how you interpret "var" in those declarations. I can see it meaning either "do type inference separately for each variable declared on this line" or "one and only one type, which is determined by the declarations on this line".
    My first gut feeling was "do inference separately" so I'd go with 1B and 2A
  • 1b
    2a
    I think a good reason to avoid options 1a, 2b and 2c is that if the author wants the same type they need only write it instead of var. Therefore treating it the same as multiple var declarations makes more sense to me.
Page 1 of 2 (21 items) 12