Replies: 15 comments
-
How would withers via function call maintain parameter order? The prototype point adding Z to the existing X and Y works as the last param, but what if you add Alpha to a Color containing rgb? Which 3 ints does the old code populate? |
Beta Was this translation helpful? Give feedback.
-
In order to maintain any compatibility, when adding a new member you would need to add back-compat overloads for the constructor and the With methods, otherwise the previously compiled calls would simply fail, regardless of order. Re-ordering of parameters would generally be a breaking change, like it is for all methods today. |
Beta Was this translation helpful? Give feedback.
-
"Withers" are another problem solved very neatly with the builder pattern. The instance offers a virtual method which returns the mutable builder using the original instance as the prototype. The developer can then modify the members at will and call the virtual build method to get a new instance with the modified members. All of the implementation details are hidden behind the black box and the addition of new members does not break the interface. |
Beta Was this translation helpful? Give feedback.
-
I strongly agree with @HaloFour here. it's also a very nice (IMO) naming pattern that would be clear for non-C# languages to consume/produce. It feels strange to me that we aren't considering that approach. @HaloFour would you be willing to write up a gist to show this in action? |
Beta Was this translation helpful? Give feedback.
-
I tried the builder approach in #1667 but ended up hitting a wall when working across inheritance. |
Beta Was this translation helpful? Give feedback.
-
What wall specifically? Could you demonstrate some of the syntax where this poses a problem? I'd like to see if there are alternative approaches or trade-offs that could be made that would enable it to succeed. |
Beta Was this translation helpful? Give feedback.
-
The main problem is resiliency to moving the property down to a base type. I designed a striping system where each type had its own struct with its own fields, but the second you want to move a field from the derived to the base you have to remove it from the derived struct (and this is a breaking change) |
Beta Was this translation helpful? Give feedback.
-
Admittedly I can see the challenge in trying to adapt struct-based builders over inherited types. In the Java world the builders would be proper classes with virtual dispatch which very neatly hides all of the details away, for lack of any other construct to use. But I can understand that having an additional allocation per allocation being distasteful. I still think that there is a solution here and I will plug away at it. I still think that there is an approach here that can build on existing syntax idioms. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour ". But I can understand that having an additional allocation per allocation being distasteful" -- this allocation could be a struct, and you can prove many things about its lifetime, it could be more efficient than what we think (guaranteed gen0?) -- from a discussion on one of the other stackalloc threads i seem to remember than a gen0 allocation was about as expensive as 3 function calls? -- if so, then the function call overhead of the builder could be bigger than the alloc overhead |
Beta Was this translation helpful? Give feedback.
-
I'm referring specifically to a heap allocation. Even if the allocation itself is quick and almost guaranteed to be gen0 it's still something that the GC needs to deal with. Thoughts on this design? https://gist.github.com/HaloFour/bccd57c5e4f3261862e04404ce45909e Is it similar to the approach you tried? |
Beta Was this translation helpful? Give feedback.
-
@agocke Is there a shortcoming in @HaloFour's gist in the previous comment? I really like the builder approach too. |
Beta Was this translation helpful? Give feedback.
-
This is good. It moves a lot of the bloat to calculated properties, instead of to fields. Right now I think we're settling out on design questions. If it turns out that this is better implementation-wise, I'm fine with that. What would the proposal be for struct records? Still use a builder? |
Beta Was this translation helpful? Give feedback.
-
Regarding LDM on Feb 5, 2020 We were told that Code Contracts (in the language) would not be needed because nullable reference types would cover 90% of cases. And I mostly agree. But what I see now that more and more special attributes are being added for control flow analysis for NRT. It is already a mess with these attributes with very confusing names and very subtle behaviour. Particularly in that LDM new attributes are discussed, and I cannot remember how many times before similar attributes where discussed. I believe that for CFA code contracts is a perfect fit and I'm wondering why they are not considered as a general solution. As an example, here's how these annotations can be encoded: static void M([EnsuresNotNull(nameof(Point.X))]Point p) { ... }
// would be
static void M(Point p)
ensures p.X != null
{ ... }
static void M([EnsuresNotNull("P1.X", "P1.Y")]Line l) { ... }
// would be
static void M(Line l) ensures l.X != null && l.Y != null { ... }
// or
static void M(Line l)
ensures l.X is not null
ensures l.Y is not null
{ ... }
static bool M([EnsuresNotNullWhen(true, "P1.X", "P1.Y")]Line l) { ... }
// would be
static bool M(Line l)
ensures !return || l.X is not null && I.Y is not null // it is better to have implication logical operator
// ensures return implies X != null
// ensures return implies Y != null
{ ... }
[MemberNotNull(nameof(X))]
void M() { }
// would be
void M() ensures this.X != null { ... } |
Beta Was this translation helpful? Give feedback.
-
Code contracts as they were proposed would affect the semantics of the program. Violating the contract could result in a runtime exception or fail-fast, depending on who you asked. NRTs were designed specifically so that they would have zero runtime impact. The design around code contracts seems to have stalled in general. |
Beta Was this translation helpful? Give feedback.
-
@HaloFour I see the point about runtime implication, but what I was thinking is only metadata that would be available for the compiler as for control flow analysis. Regardless of what is the runtime implementation would be chosen, this metadata should be available. If it'd be known how the metadata might be encoded in the signature (a special attribute or so), that could be used for this feature as well. As for how to specify the contract without impacting the implementation can be discussed. I believe that the runtime code inserted should be optional for code contracts at all and should be considered the implementation detail. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Feb 5
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-02-05.md
Feb 3
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-02-03.md
Value Equality
Jan 29, 2020
https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-01-29.md
Records: "With-ers"
Beta Was this translation helpful? Give feedback.
All reactions