csharplang/meetings/2017/LDM-2017-03-15.md
2017-04-04 15:17:33 -07:00

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.