3.7 KiB
C# Language Design Notes for Mar 15, 2017
Raw notes, yet to be cleaned up - read at your own peril
Triage
JSON literals
No
Fixing captured locals
Not worth any effort, probably even up for grabs
Allow shadowing of parameters
Current rule saves your bacon a couple of times
var t = FooAsync(...)
t.ContinueWith(t => ... ); // whoops
Discards would make this worse, in a sense, because they lead people to be more likely to capture.
Shadowing could be used to avoid capturing, but that would be better served by a non-capture feature. Could be a static
on lambdas to avoid capture - or it could be a capture list approach.
"Capture nothing", "capture what I want", "capture this" are three levels with different cost.
Could be this
, static
and nothing in front of the lambda. But it might be nice to have an explicit annotation for the default, for people who care to express that they explicitly thought about it.
Individual items is worthless if you don't care about different kinds of capture for a given variable.
Also a great candidate for custom annotations so we don't put it in the language. That would also allow folks that want more detail to have that.
Attributes on lambdas seem like a more general feature. Let's feed this in as a scenario for attributes on lambdas.
Weak delegate
Best approach is the small leak pattern which creates a wrapper delegate with a weak reference to the original receiver. That doesn't solve the whole problem, though - how about unregistrering, etc?
"Little leek - isn't that called a spring onion?"
This isn't necessarily a language feature. This should be a library that you pass the method to, and it wraps it. It would be helped by a delegate constraint.
Conclusion: Not as a language feature right now; figure it out as a library feature, and maybe, someday we would add syntax around it.
Protocols/duck typing/concepts/type classes
More dynamic or more static approaches to "adding a 'type' after the fact".
A separate important subissue is the dependency explosion.
Different solutions to the same problem. They should be addressed as one design effort.
8.0 is crazy, but helps us prioritize investigation work
0 and 1 element tuples
var () = e; // who cares to deconstruct?
var (x) = e; // just get through property?
var (x, (y)) = e; // recursive - can't just grab a member
In other languages ()
are list-like unit type things.
() M(...) => (); // returns zero things
Also if we ever go to bool-returning Deconstruct methods (or the like), you might want zero-length decosntructors to mean "there wasn't anything".
Womples are more likely to be useful, especially for deconstruction. But they are also the ones that clash most fiercely with existing syntax (parenthesized expressions!).
() t = ();
(int x) = (5);
(int x) = (d); // could go either way - deconstruct a womple, or deconstruct d?
Probably not that useful to have womple expressions. Could allow using named element(s) or even :
alone:
var t = (x: 3);
var t = (: 3); // yuck!
On a deconstruction side:
(x) = e;
(x, (y)) = e;
that already means something today. You could do:
(x: x) = e;
(: x) = e;
We would have
if (o is OneDPoint(3)) ...
if (odp is (3)) ...
Resolve this with
"Who's champion for recursive patterns? It says "see champion for recursive patterns".
Deconstruction in lambda parameters
It's a special case of deconstruction in parameters
(var (x, y)) => x + y;
double M((int x1, int y1), (int x2, int y2)) => Sqrt(x1 * x2 + y1 * y2);
private protected
Would not use so much in the BCL, but in APIs with deeper hierarchies, definitely.