3 ms·
I think this stems from having properties, which are synthetic sugar for a backing-field and a getter & setter function. This muddies the water between just se
by OptionOfT 1y ago
I think this stems from having properties, which are synthetic sugar for a backing-field and a getter & setter function.
This muddies the water between just setting a field vs executing a function that does work and then sets the field.
If I write a record with an explicit setFoo(foo: Foo) I wouldn't expect a clone & subsequent direct field assignment to execute the setFoo(foo: Foo) code.
- louthy 1y ago> wouldn't expect a clone If I create a new object I would expect the 'init time' properties to be initialised. Regardless of how it was initialised. The current approach just leads to inconsistent data structures, with significant issues for debugging how a data structure got into an inconsistent state. Modern language features should not be trying to save nanoseconds like they did in the past. Or, should at least default to 'correct' with performance opts outs.
- OptionOfT 1y agoYou don't even need to use the `with` operator to get into an inconsistent state: using System; // same behavior with // public sealed class Inner public struct Inner { public int Value { get; set; } } // same behavior with // public sealed record class Outer(Inner Inner) public record struct Outer(Inner Inner) { public bool Even { get; } = (Inner.Value & 1) == 0; } class Program { public static void Main(string[] args) { var inner = new Inner { Value = 42 }; var outer = new Outer(inner); inner.Value = 43; Console.WriteLine("{0} is {1}", inner.Value, outer.Even); } } Would you expect Even to be updated here?
- louthy 1y agoSure, but you’re talking about a 25 year old feature (structs). One that was implemented like that for performance reasons in C# 1.0 – because we were all using single or dual core machines back then. Records were a relatively recent feature addition, computers are significantly more powerful, and our programs are significantly more complex. And so it’s hella frustrating that MS didn’t opt for program correctness over performance. They even missed the opportunity to close the uninitialised struct issue with record structs (they could have picked different semantics). I find their choices utterly insane when we’re in a world where bad data could mean a data breach and/or massive fine. The opportunity to make records robust and bulletproof was completely missed. I was hoping that we’d get to a set of data-types in C# that were robust and correct: product-types and sum-types. With proper pattern matching (exhaustiveness checking). Then either a Roslyn analyser or a C# ‘modern mode’ which only used the more modern ‘correct’ features so that we could actually go away from the compromises of the past. Unfortunately many modern features of C# are being built with these ugly artefacts seeping in. It’s the opposite of declarative programming, so it just keeps increasing incidental complexity: it exports the complexity to the users, something a type-safe compiler should be reducing.