Replies: 14 comments
-
The feedback on primary constructors is interesting. All of the languages that I'm aware of (namely Scala, Kotlin and F#) all behave more or less as was originally planned, in that the constructor parameters are only captured (effectively fields) in the body of the type and no additional members are surfaced unless you do so manually or apply another keyword which promotes them to public properties. Having primary constructor parameters automagickally become properties in a non-record scenario doesn't feel right to me. Maybe the problem is trying to marry primary constructors and |
Beta Was this translation helpful? Give feedback.
-
I'd add Java to that list as well, but only sort of, both because the record feature is experimental in Java 14 and because at least as of now you can't have a primary constructor without the keyword to denote that the type is a record. |
Beta Was this translation helpful? Give feedback.
-
So there will be no standalone primary constructor feature? That's unfortunate. The original premise was that it could remove constructor boilerplate for all types? |
Beta Was this translation helpful? Give feedback.
-
I feel like this is discomfort with what sounds like something strange, but in practice my experience with scala is that this isn't an issue. The user rarely cares whether or not the parameter has been captured, and doesn't really need to know that there's a difference in semantics between them. However the difference in semantics is useful as it allows the compiler to optimize away otherwise unnecessary fields. This reminds me a little of https://gafter.blogspot.com/2017/06/making-new-language-features-stand-out.html |
Beta Was this translation helpful? Give feedback.
-
I don't think that's what we're thinking this means (or at least that's not what I thought it meant.) We're still exploring the primary constructor space, and the thought is that we make it always do the same thing, regardless of whether it's applied to a record type or not. The notes only mention public properties there, but my theory is that you'd be able to apply access modifiers. We'll be talking about them more tomorrow iirc. |
Beta Was this translation helpful? Give feedback.
-
So you'd get properties by default? What would the default access be without a modifier? How does |
Beta Was this translation helpful? Give feedback.
-
All good questions that we'll be working on tomorrow :) |
Beta Was this translation helpful? Give feedback.
-
@HaloFour if I understand your point correctly, it's that scala effectively does what we were planning by using That does seem to work fine for them, but this position was controversial in the review. |
Beta Was this translation helpful? Give feedback.
-
Correct. The details are different for each of the mentioned languages but in all of the cases the primary constructor alone isn't enough to result in public members being generated. What the primary constructor parameters are internally to the class and how you can work with them differ between each of the languages, though. In Kotlin they are only available as parameters for member initializers and an initializer block, but are not captured for use in other members like functions. You can add modifiers with In F# they are available as parameters but also captured and can be used in functions, but not like fields (can't be qualified by In Scala they are indistinguishable from fields. Adding In Java you can't use them without the I'm curious how other languages handle it as clearly there isn't a one-side-fits-all. Out of the above I kind of like Scala's approach the best. |
Beta Was this translation helpful? Give feedback.
-
I went back and looked at a bunch of languages here. What we we're generally talking about is "positional records" and what I found was that almost all languages that have positional records design them how you're describing. There are a few languages, like F# and Rust, that don't really have positional records in this sense. But those languages also have something else in common, which is that they have a separate discriminated union syntax that generates what looks like positional records. My impression here is that concision of representing data models effectively forces a positional-like syntax form. If you want to construct your discriminated unions out of your records feature, I think that implies some form of positional records is necessary. If that doesn't matter then you use a separate syntax for ADTs. |
Beta Was this translation helpful? Give feedback.
-
You could add Swift to that list as well: enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
} From what I understand single case unions are pretty common in F#, particularly to model primitive type wrappers. |
Beta Was this translation helpful? Give feedback.
-
I hate the idea of having a magic Jupyter notebooks will likely be old news in a few years like most programming fads, the decisions you make now will stick around in C# forever. Please stick to the pit of success. |
Beta Was this translation helpful? Give feedback.
-
I disagree with you about the args parameter. The way I see it, simple programs must be a natural stepping stone towards complex programs. If you use args in Main you should be able to use args in a simple program and in exactly the same way. I could agree that perhaps it should only be available in the top level sentences, not in any of the subroutines to nudge people away from globals, even though local functions inside Main have access to args. |
Beta Was this translation helpful? Give feedback.
-
IMO it is a good thing to have different behavior between records and classes. If they both behave the same way, why would I use one other the other. With that said I would suggest the following: Foo(string name, string lastname); And instead of caring about access modifiers we could just decide that if properties are generated they are always Foo(prop string name, prop string lastname); I know that this is introducing a new keyword, but at least it is meaningful and easy to spot on code reviews. Foo(string name, string lastname, prop string displayName); I also understand that there are cases where one needs private properties or even init-only properties in classes, but I would argue that those cases are so rare, that for those cases one can just write usual classes definitions with regular constructors. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
May 6, 2020
C# Language Design Notes for May 6, 2020
if (x is not string y)
pattern.GetEnumerator
May 4, 2020
C# Language Design Notes for May 4, 2020
Beta Was this translation helpful? Give feedback.
All reactions