csharplang/meetings/2017/LDM-2017-04-18.md
2017-04-19 17:14:50 -07:00

3.9 KiB

C# Language Design Notes for Apr 18, 2017

Raw notes, yet to be cleaned up - read at your own peril

Quote of the Day: "I don't want to require MainAsync. It sounds like mayonnaise-ink!"

DIM Event accessors

Today, syntactically, either both or neither accessor can have an implementation.

Should we allow just one to be specified? Overridden?

Conclusion

If you have only one, you probably have a bug. Let's not allow it. Not blocked for future idiots to ...

DIM Reabstraction

Yes, adding a body to an interface member declaration shouldn't break C.

DIM Sealed override

Should it be allowed? would it prevent overrides in classes or only in interfaces?

It seems odd to prevent either. Also, it is weird in connection with diamond inheritance: what if one branch is sealed?

Conclusion

Let's not allowed sealed on overrides in interfaces. The only use of sealed on interface members is to make them non-virtual in their initial declaration.

DIM sealed members (not on list)

Some folks in the community find it weird, and that they look too much like things that can be implemented in classes.

Conclusion

We think it is going to be useful, but will come back to it. This is a mental model tripping block.

DIM not quite implementing a member (not int list)

You have a member and implement an interface. The interface adds a new member with a default implementation, that looks like your method but doesn't quite make it an implementation. Bug? Intentional? We can't provide a warning, because it would assume it was a bug.

Conclusion

Can't do anything about this.

DIM implementing inaccessible interface members (not in list)

The way the runtime works today, a class member can happily implement an interface member that isn't accessible! That's not likely to be dependent on today (no language will generate that interface), but we need to decide what semantics to have here.

We could continue to only have public members in interfaces be virtual. But if we want protected, internal and private, we should probably have it so they can only be implemented by classes that can see them. But this means that interfaces can prevent other assemblies from implementing them! This may be a nice feature - it allows closed sets of implementations.

Conclusion

This is still open, but our current stake in the ground is we should allow non-public virtual interface members, but disallow overriding or implementing them in places where they are not accessible.

DIM Implementing a non-public interface member (not in list)

Would we allow them to be implemented implicitly? If so, what is required of the accessibility of the implementing method?:

  • Must be public
  • Must be the same accessibility
  • Must be at least as accessible

Conclusion

For now, let's not allow any of these. We can relax as we think through it.

Async Main code generation

In the compiler we look for shapes of types. If somebody has a weird implementation of Task or Task<T>, their GetAwaiter().GetResult() returning something else.

This is about consuming an awaitable, not producing one. So not just about Task and Task<T>? After all we just made the language less dependent on those specific types.

It would not add complexity on the implementation side, it's just about whether we check for those specific types.

On the other hand, if we don't allow it, folks can just have an async Task Main that awaits it.

One problem is that current awaitable things aren't necessarily built to block on GetResult(). It may not work right.

Conclusion

Let's still keep the async keyword optional.

Let's stick with Main instead of MainAsync for now.

Let's refine the rule:

  1. Look for Main() or Main(string[] args)
  2. Does exactly one return void or int? If one, use that. If more, error.
  3. Otherwise, look for Task and Task<T>, where the return type of GetAwaiter().GetResult() is int or void.