# C# Design Notes for Dec 16, 2013 ## Agenda This being the last design meeting of the year, we focused on firming up some of the features that we’d like to see prototyped first, so that developers can get going on implementing them. 1. Declaration expressions <_reaffirmed scope rules, clarified variable introduction_> 2. Semicolon operator <_reaffirmed enclosing parentheses_> 3. Lightweight dynamic member access <_decided on a syntax_> ## Declaration expressions On Sep 23 we tentatively decided on rules for what the scope is when a variable is introduced by a declaration expression. Roughly speaking, the rules put scope boundaries around “structured statements”. While this mostly makes sense, there is one idiom, the “guard clause” pattern, that falls a little short here: ``` c# if (!int.TryParse(s, out int i)) return false; // or throw, etc. … // code ideally consuming i ``` Since the variable `i` would be scoped to the if statement, using a declaration statement to introduce it inside of the if would not work. We talked again about whether to rethink the scope rules. Should we have a different rule to the effect essentially of the variable declaration being introduced “on the preceding statement”? I.e. the above would be equivalent to ``` c# int i; if (!int.TryParse(s, out i)) return false; // or throw, etc. … // code consuming i ``` This opens its own can of worms. Not every statement _has_ a preceding statement (e.g. when being nested in another statement). Should it bubble up to the enclosing statement recursively? Should it introduce a block around the current statement to hold the generated preceding statement, etc. More damning to this idea is the issue of initialization. If a variable with an initializer introduced in e.g. a while loop body is understood to really be a single variable declared outside of the loop, then that same variable would be re-initialized every time around the loop. That seems quite counterintuitive. This brings us to the related issue about variable lifetimes. When a variable is introduced somewhere in a loop, is it a fresh variable each time around? It would probably seem strange if it weren’t. In fact we took a slight breaking change in C# 5.0 in order to make that the case for the loop variable in `foreach`, because the alternative didn’t make sense to people, and tripped them up when they were capturing the variable in lambdas, etc. ### Conclusion We keep the scope rules described earlier, despite the fact that the guard clause example doesn’t work. We’ll look at feedback on the implementation and see if we need to adjust. On variable lifetimes, each iteration of a loop will introduce its own instance of a variable introduced in the scope of that loop. The only exception is if it occurs in the initializer of a for loop, because that part is evaluated only on entry to the loop. ## Semicolon operator We previously decided that a sequence of expressions separated by semicolons need to be enclosed in parentheses. This is so that we don’t get into situations where e.g. commas and semicolons are interspersed among expressions and it isn’t visually clear what the precedence is. We discussed briefly whether those parentheses are necessary even when there is other bracketing around the semicolon-separated expressions. ### Conclusion It’s not worth having special rules for this. Instead, semicolons are a relatively straightforward addition to parenthesized expressions – something like this: > _parenthesized-expression:_ > * `(` *expression-sequence*\_opt expression_ `)` > _expression-sequence:_ > * *expression-sequence*\_opt _statement-expression_ `;` > * *expression-sequence*\_opt _declaration-expression_ `;` ## Lightweight dynamic member access On Nov 4 we decided that lightweight member access should take the form `x.Foo` for some value of ``. One candidate for the glyph is `#`, so that member access would look like this: ``` c# payload.#People[i].#Name ``` However, `#` plays really badly with preprocessor directives. It seems almost impossible to come up with syntactic rules that reconcile with the deep lexer-based recognition of `#`-based preprocessor directives. After searching the keyboard for a while, we settled on ‘`$`’ as a good candidate. It sort of invokes a “string” aspect in a tip of the hat to classic Basic: ``` c# payload.$People[i].$Name ``` One key aspect of dynamicness that we haven’t captured so far is the ability to declaratively construct an object with “lightweight dynamic members”, i.e. with entries accessible with string keys. A core syntactic insight here is to think of `$Foo` above as a unit – as a “lightweight dynamic member name”. What this enables is to think of object construction in terms of object initializers – where the member names are dynamic: ``` c# var json = new JsonObject { $foo = 1, $bar = new JsonArray { "Hello", "World" }, $baz = new JsonObject { $x = 1, $y = 2 } }; ``` We could also consider allowing a free standing `$Foo` in analogy with a free standing simple name being able to reference an enclosing member in the implicit meaning of `this.$Foo`. This seems a little over the top, so we won’t do that for now. One thing to consider is that objects will sometimes have keys that aren’t identifiers. This is quite common in Json payloads. That’s fine as far as member access is concerned: just fall back to indexing syntax when necessary: ``` c# payload.$People[i].["first name"] ``` It would be nice to also be able to initialize such “members” in object initializers. This leads to the idea of a generalized “dictionary initializer” syntax in object initializers: ``` c# var payload = new JsonObject { ["first name"] = "Donald", ["last name"] = "Duck", $city = "Duckburg" // equivalent to ["city"] = "Duckburg" }; ``` So just as `x.$Foo` is a shorthand for `x["Foo"]` in expressions, `$Foo=value` is shorthand for `["Foo"]=value` in object initializers. That syntax in turn is a generalized dictionary initializer syntax, that lets you index and assign on the newly created object, so that the above is equivalent to ``` c# var __tmp = new JsonObject(); __tmp["first name"] = "Donald"; __tmp["last name"] = "Duck"; __tmp["city"] = "Duckburg"; var payload = __tmp; ``` It could be used equally well with non-string indexers. A remaining nuisance is having to write all the type names during construction. Could some of them be inferred, or a default be chosen? That’s a topic for a later time. ### Conclusion We’ll introduce a notion of dictionary initializers `[index]=value`, which are indices enclosed in `[…]` being assigned to in object initializers. We’ll also introduce a shorthand `x.$Foo` for indexing with strings `x["Foo"]`, and a shorthand `$Foo=value` for a string dictionary initializer `["Foo"]=value`.