-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C# Language Design Review, Mar 25, 2015 #1921
Comments
There was a proposal on Codeplex to have a uniform treatment of To make this rule even more universal, you could do some of the following:
|
Thanks for the update. I'm really happy to hear that an expression form for pattern matching is being considered. This will really add to the conciseness and usability of the feature. |
On 5) Records, I think the point made about GetHashCode is a great example of why auto-generation of GetHashCode, Equals, and ToString (and With) should be a distinct feature from the primary constructor syntax. This is what the Tying the two features together never made much sense- it makes not using a primary constructor have a very high cost because you lose so much functionality. |
Regarding 3) Code Contracts should definitely be able to throw exceptions, otherwise it'd be impossible to test them with unit-tests. |
Additionally, it was mentioned that you wouldn't want to kill an entire web server process just because one of its hosted websites encountered a contract violation. |
The way I see it, method contracts are simply a set of pre and postconditions that are defined at the language level with the advantage that its easier to document and do flow analysis for. They should replace the classic parameter validation block at the beginner of a method. |
Since there has been so much discussion regarding code contracts, probably the best solution would be the throw exceptions but have an option to intercept them (like I don't think there's enough justification to replace |
I like the idea of having pattern matching fit in with existing The only flavor of that which looks kind of weird to me is the type pattern: object x = ...;
if (x is MyClass y) {
// use y here
} Something about that just looks a little backwards to me. I do like the idea of an expression operator like Shape shape = ...;
double area = match(shape) {
// multiple statement
Circle(radius) => {
double diameter = radius * 2;
return diameter * Math.PI;
},
// single expression
Square(length) => length * length,
Rectangle(width, height) => width * height,
// or default?
* => throw new InvalidOperationException()
}; |
F# has a similar syntax for |
I propose that we should use the character / symbol MustInherit Class PE_Header
Protected Friend _b(112) As Byte
Friend Sub New( b As Byte())
_b = b
End Sub
Public ReadOnly Property Magic As UInt16 = _b( 0:2)
Public ReadOnly Property MajorLinkerVersion As Byte = _b( 2:1)
Public ReadOnly Property MinorLinkerVersion As Byte = _b( 3:1)
Public ReadOnly Property SizeOfCode As UInt32 = _b( 4:4)
Public ReadOnly Property SizeOfInitializedData As UInt32 = _b( 8:4)
Public ReadOnly Property SizeOfUninitializedData As UInt32 = _b(12:4)
Public ReadOnly Property AddressOfEntryPoint As UInt32 = _b(16:4)
Public ReadOnly Property BaseOfCode As UInt32 = _b(20:4)
Public ReadOnly Property ImageBase As UInt32 = _b(28:4)
End Class
Public Class PE_Header_32
Inherits PE_Header
Public Sub New( b As Byte())
MyBase.New( b )
End Sub
Public ReadOnly Property BaseOfData As UInt32 = _b(24:4)
End Class
Public Class PE_Header_32
Inherits PE_Header
Public Sub New( b As Byte())
MyBase.New( b )
End Sub
Public Shadows ReadOnly Property ImageBase As UInt64 = _b(24:8)
End Class |
Design notes have been archived at https://github.com/dotnet/roslyn/blob/future/docs/designNotes/2015-03-25%20C%23%20Design%20Review.md but discussion can continue here. |
C# Language Design Review, Mar 25, 2015
We've recently changed gears a little on the C# design team. In order to keep a high design velocity, part of the design team meets one or two times each week to do detailed design work. Roughly monthly the full design team gets together to review and discuss the direction. This was the first such review.
Agenda
Initial port and addition of README.md #1. Overall direction
In these first two months of design on C# 7 we've adopted a mix of deep dive and breadth scouring. There's agreement that we should be ambitious and try to solve hard problems, being willing to throw the result away if it's not up to snuff. We should keep an open mind for a while still, and not lock down too soon on a specific feature set or specific designs.
#2. Nullability features
Non-nullable types are the number one request on UserVoice. We take it that the underlying problem is trying to avoid null reference exceptions. Non-nullable types are at best only part of the solution to this. We'd also need to help prevent access when something is nullable.
We've looked at this over a couple of design meetings (#1303, #1648). Ideally we could introduce non-null types, such as
string!
that are guaranteed never to be null. However, the problems around initialization of fields and arrays, etc., simply run too deep. We can never get to full guarantees.We've been mostly looking at implementation approaches that use type erasure, and that seems like a promising approach.
However, the thing we need to focus on more is this: when you get a nullability warning from this new feature, how do you satisfy the compiler? If you need to use unfamiliar new language features or significant extra syntax to do so, it probably detracts from the feature.
Instead we should at least consider an flow-based approach, where the "null-state" of a variable is tracked based on tests, assignments etc.
It's an open question how far we would go. Would we track only locals and parameters, or would we also keep track of fields?
This is more problematic, not just because of the risk of other threads changing the field, but also because other code may have side effects on the field or property.
TypeScript uses information about type guards to track union types in if branches, but it's not full flow analysis, and works only for local variables. Google Closure is more heuristics based, and is happy to track e.g.
foo.bar.baz
style patterns.A core nuisance with nullability checking is that it raises a wealth of compat questions that limit the design in different ways. There may need to be some sort of opt-in to at least some of the diagnostics you'd get, since you wouldn't want them if you were just recompiling old code that used to "work".
#3. Performance and reliability
The list produced at a recent design meeting (#1898) looks sensible.
val / readonly
We should cross check with Scala on their syntax.
ref return / locals
Lots of compexitity - we question whether it is worth the cost?
Never type
The type system approach is interesting, and allows throw expressions.
Method contracts
requires
/ensures
, show up in docs, etc. This looks great. The biggest question is what happens on failure: exceptions? fail fast?Slices
We got strong feedback that array slices are only interesting if we unify them with arrays. Otherwise there's yet another bifurcation of the world. There's some value to have a
Slice<T>
struct type just show up in the Framework. But it really doesn't seem worth it unless it's a runtime feature. That unification is really hard to achieve, and would require CLR support. It's valuable enough to try to pursue even with high likelihood of failure.Slicing as a language syntax could also be "overloadable" - on IEnumerables for instance.
In Go, if you treat a slice as an object, it gets boxed.
Lambda capture lists
Not interesting as a feature, but the idea of allowing attributes on lambdas might fly.
Immutable types
General concern that this doesn't go far enough, is lying to folks, etc. It tries to have strong guarantees that we can't make.
But a lot of people would appreciate something here, so the scenario of immutability should continue to motivate us.
Destructible types
The scenario is good, not the current proposal.
#4. Tuple types
There's agreement on wanting the feature and on the syntax (#347, #1207).
We probably prefer a value type version of Tuple. Of course those would be subject to tearing, like all structs. We're willing to be swayed.
There are performance trade offs around allocation vs copying, and also around generic instantiation. We could do some experiments in F# source code, which already has tuples.
#5. Records
See #180, #206, #396, #1303, #1572.
In the current proposal, we should just give up on the ability to name constructor parameters and members differently. The motivation was to be able to upgrade where parameter names start with lower case and member names upper case, but it's not worth the complexity.
Should it have
==
and!=
that are value based? Clashes a little with the ability to make them mutable.If I introduce extra state, then I have to write my own GetHashCode. That seems unfortunate.
All the gunk today is part of why Roslyn uses XML to generate its data structure. A test of success would be for the Roslyn syntax trees to be concise to write in source code.
A big issue here is incremental non-destructive modification. Roslyn follows the pattern of "Withers", a method for each property that takes a new value for that property and returns a new object that's a copy of the old one except for that property. Withers are painfully verbose to declare, and ideally this feature would offer a solution to that.
Serialization has to work somehow, even though many of the members will be generated.
We should not be too concerned about the ability to grow up to represent all kinds of things. Start from it being the POD feature, and work from there.
#6. Pattern matching
See #180, #206, #1572.
Whether introduced variables are mutable or not is not a key question: we can go with language uniformity or scenario expectation.
Integral value matching is an opportunity to generalize. The pattern 3 may match the value 3 of all integral types rather than just the int 3.
Named matching against all objects and positional against ones that define a positional match. Are recursive patterns necessary? No, but probably convenient and there's no reason not to have them.
Pattern matching could be shoe-horned into current
switch
statements as well asis
expressions. And we could have a switching expression syntax as well:An expression version would need to be checked by the compiler for completeness. A little clunky, but much more concise than using a switch.
Similar to a current pattern in the Roslyn code base:
Maybe the fat arrow is not right. We need to decide on syntax. Another option is to use the case keyword instead.
The text was updated successfully, but these errors were encountered: