Replies: 33 comments
-
I like the I also like the I'm not sold on primary constructors. As mentioned in the notes, the value of primary constructors for records are a lot less useful if you can't easily use them for types that are going to be serialized. And types that will be serialized is doubtless one of the primary use cases of a record class.
I disagree with this. Any programmer above the level of novice should be able to understand the implications of mutating an object that is keyed into a Dictionary. I detest when warnings are added that warn about legitimate patterns that might be a mistake. (Like 4014) |
Beta Was this translation helpful? Give feedback.
-
Let me rephrase this slightly. I don't think "they should know better" is a good argument because, tbh, I make plenty of mistakes when I'm tired and at any given day I'm probably an advanced programmer and worse than novice, depending on my state of mind. But, I think you have a better argument. In general, if we're going to add a warning to a pattern that might be OK, we usually try to add a mechanism to silence that warning -- basically an indication to the compiler that you're in a less common scenario, but what you're doing is perfectly safe. If we did give you a warning, I don't see how you would silence it. Implementing equals yourself isn't really a solution -- that's what we're trying to help with in the first place. Making your class immutable isn't great either -- if you're not adding it to a dictionary, what's the problem? So maybe the warning on the type isn't a good idea. There may be some useful information we could provide here, but let's scope it close to the actual problem. |
Beta Was this translation helpful? Give feedback.
-
With regards to indicating that a property must be initialised at the call site, I think it's worth considering that in conjunction with #2328, which tries to do the same for non-nullable properties. Whilst this could be solved by making non-nullable properties initonly, that would be a breaking change. |
Beta Was this translation helpful? Give feedback.
-
Can we please get an issue corresponding to the PR to facilitate conversation? I'm a little confused as to why the LDM is taking this approach to publishing new proposals. It hinders dialog. We had to have a community member create an issue for Primary Constructors. I'm still not sold on the idea of |
Beta Was this translation helpful? Give feedback.
-
As far as I see, the principal difference of the new records proposal is that is allows the use of object initializers with read-only properties, i.e., #1684 |
Beta Was this translation helpful? Give feedback.
-
@HaloFour honestly, I thought this was the issue. It's strictly more complete because it also has LDM notes. If you want a separate issue I can do that next time, though. Regarding verification: we already abandoned it in C# 7.3 when we started taking refs to readonly variables. Nothing checks it except for partial trust and no new languages are supported on the desktop framework anyway. |
Beta Was this translation helpful? Give feedback.
-
@agocke |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox certainly related, but this one is opt in and has setters. |
Beta Was this translation helpful? Give feedback.
-
Having the design notes is good, but given that these notes span multiple topics I think it's better to have a separate proposal issue as well. Otherwise there is a big risk of multiple conversations starting on multiple subjects and that can be very difficult to follow on Github. It's bad enough when there are multiple conversations on one subject.
You mean language features? Most of 8.0 is supported, if unofficially, on .NET Framework, if only they need to be enabled via NuGet packages. Is the official position of the C# team that the language evolution will drive forward without consideration to the users still on .NET Framework? That seems like a poor choice, similarly poor to the language/runtime changes that have left lasting schisms in the Python, Perl and Java communities. Even assuming all existing still-maintained projects have a trajectory to migrate to .NET Core it will still probably take quite some time to get there and the further the language evolves/diverges the harder it will be. So I'd hope that the C# team would consider not breaking support for .NET Framework and downlevel compilers/runtimes unless there is compelling reasons to do so. Runtime verification aside, my concern is more about how easy it will be for downlevel compilers or other languages to simply disregard this notion of "initonly" and to enable writing to those properties at any time. Is Furthermore, is late-initialization something I can buy into without having to use the |
Beta Was this translation helpful? Give feedback.
-
Thanks for the feedback, I've split out everything but records to #2702 |
Beta Was this translation helpful? Give feedback.
-
@agocke Thanks! 😃 |
Beta Was this translation helpful? Give feedback.
-
I think we consider changing the CLR to be a tool in our toolbox, which implies that we may leave .NET Framework in the wind. For verification specifically, even C# 7.3 does not consider peverification to be an important scenario. That in particular is not something we'll go out of our way to preserve. |
Beta Was this translation helpful? Give feedback.
-
I don't disagree with this, but I'd hope that C# features that would entail changes to the runtime would have to meet a fairly high bar. Even discounting the .NET Framework, you'll have to deal with release and LTS cycles for .NET Core, which will (temporarily) fracture the user base. There's also the question of support across the ecosystem of .NET languages, including downlevel compilers . With the I'm of the opinion that "records" are a minor evolution of existing POJOs and that the compiler support could build on existing conventions rather than define new and incompatible ones. I'm also of the opinion that "records" should be designed very closely with discriminated unions, even if they are based on orthogonal features and don't ship in the same release. It would be a shame if any aspect of "records" might end up being incompatible with the design of discriminated unions. |
Beta Was this translation helpful? Give feedback.
-
I don't think that's true. The |
Beta Was this translation helpful? Give feedback.
-
Exactly, C# 8.0 can't create instances of this type and set these values. Neither can any other compiler or any other tools, until they're updated. At best they can only consume them. At worst they would be confused by the metadata (particularly if the |
Beta Was this translation helpful? Give feedback.
-
Yes, probably, I'm terrible at branding 😄 |
Beta Was this translation helpful? Give feedback.
-
I'm very interested in primary constructors, but I'm not quite sure what the spec is proposing regarding them in regular classes. In my mind, this: class Point(int x, int y)
{
} ...should be exactly equivalent to: class Point
{
int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
} Please don't publish those as public properties by default for regular classes. However, for data classes, that makes sense, and I'd like to further propose the data enum Option<T>
{
None,
Some(T Value)
} |
Beta Was this translation helpful? Give feedback.
-
I think Records shouldn't be an actual feature on its own but more like a product of Primary Constructors and implicitly provided structural equality. Compact DefinitionUsing Primary Constructors (#2691) that should turn this: public class Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
} ... to this: public class Point(int X, int Y)
{
} I believe, according to the proposal it would also automatically come with Structural EqualityAn implicit implementation of With operatorI think this is the only piece that would really need a deeper level of support because for the public Point With(int X = this.X, int Y = this.Y) I think an implicit implementation of this could come with every class using a Primary Constructor, so it wouldn't be Record-specific. Extra questions
|
Beta Was this translation helpful? Give feedback.
-
@petroemil Thanks for linking the Primary Constructors spec. To respond to your comment, what if you want the brevity of a primary constructor but don't want to expose all the arguments as public properties? |
Beta Was this translation helpful? Give feedback.
-
I'm concerned about the verbose inheritance syntax. data class B(int X, int Y, int Z) : A(X, Y); This does not look verbose with the basic example but as soon as you add more properties and deeper inheritance chain it starts to look overly verbose. Example: data class PromotionalProduct (int Id, string Name, string Category, double Price, int CurrentStock, double DiscountPercent, DateTime startDate, DateTime validUntil)
:Product(int Id, string Name, string Category, double Price, int CurrentStock) I'd like a solution for this similar to Typescript's spread operator ( data class PromotionalProduct (..., double DiscountPercent, DateTime startDate, DateTime validUntil)
: Product |
Beta Was this translation helpful? Give feedback.
-
Close. A subtle part of Mads' proposal is that primary constructors would work a lot like lambdas, so the "parameters" wouldn't end up in fields at all, unless necessary. For instance, if you had something like class Point(int X, int Y)
{
public readonly int Magnitude = Math.Sqrt(Math.Square(X) + Math.Square(Y));
} The only public usage of @petroemil That's similar to this proposal, except that primary constructors wouldn't give you public fields by default. @popcatalin81 Seems like an interesting construction. I'd probably want to generalize it, since it doesn't look like it requires records. Luckily I think it's pretty orthogonal and we could bring it as an entirely separate feature. Even if the current proposal is a little verbose, it's much better than anything in the language today. |
Beta Was this translation helpful? Give feedback.
-
Maybe Primary Constructor parameters could have access modifiers public class Point(int X, int Y, private string Note) @popcatalin81 data class PromotionalProduct (int Id, string Name, string Category, double Price, int CurrentStock, double DiscountPercent, DateTime startDate, DateTime validUntil)
:Product(Id, Name, Category, Price, CurrentStock) But maybe it could also work just as a union of the parameters of all the inherited constructors. data class Product(int Id, string Name, string Category, double Price, int CurrentStock)
{
}
data class PromotionalProduct(double DiscountPercent, DateTime startDate, DateTime validUntil) : Product
{
} Or with another example... public class Log(LogType Type, string Message)
{
}
// The 'Message' property would be implicitly added to the 'ErrorLog' constructor,
// while the 'Type' parameter wouldn't because we specify it explicitly as part of the class definition
public class ErrorLog(Exception Exception) : Log { Type = LogType.Error }
{
} |
Beta Was this translation helpful? Give feedback.
-
Yes, ©&🍝 error. What concerns me about the union of parameters example: data class Product(int Id, string Name, string Category, double Price, int CurrentStock)
{
}
data class PromotionalProduct(double DiscountPercent, DateTime startDate, DateTime validUntil) : Product
{
} is that it has no "visual clue" that the listed parameters is not the complete list: |
Beta Was this translation helpful? Give feedback.
-
I don't care for the lack of visual cue and assumption as to the order and position of the inherited arguments. IMO, positional construction of a data class should be short and sweet with no more than 3-5 arguments and the language should optimize for that. If people want to use them for 20 arguments, it should be painful. |
Beta Was this translation helpful? Give feedback.
-
Not it should not. You often have data classes with this number of arguments in most above-average applications. |
Beta Was this translation helpful? Give feedback.
-
@popcatalin81 If you have that many arguments, then named construction should be used instead. The new proposal supports it, so there's no reason not to use it. |
Beta Was this translation helpful? Give feedback.
-
And in those cases there's no reason to use a primary constructor. All you add by combining the feature is positional construction and deconstruction, which makes absolutely no sense if you have a ton of properties. |
Beta Was this translation helpful? Give feedback.
-
Right, it was intended that things like Roslyn's CompilationOptions would use a record without a primary constructor while small things like Notably, records with primary constructors make it a breaking change to add or reorder members, and if you have 20 parameters, it's likely you'll have 21 at some point. |
Beta Was this translation helpful? Give feedback.
-
So, are Records mutable or immutable? |
Beta Was this translation helpful? Give feedback.
-
In my design, a record would be based on how you declare it. So if you have data class C
{
public int P1 { get; set; }
public int P2 { get; set; }
} then those properties would be mutable. |
Beta Was this translation helpful? Give feedback.
-
Design notes and feature notes
July 22nd
Beta Was this translation helpful? Give feedback.
All reactions