Discussion: complex nested with
expressions
#77
Replies: 15 comments 1 reply
-
@orthoxerox Your examples are too complicated that lose the point. I'd suggest you to demonstrate a single case along with its equivalent code at a time. That might help to understand what is going on. |
Beta Was this translation helpful? Give feedback.
-
@alrz Good idea, I've rewritten the OP. |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox Thanks for proposing this. The current "withers" proposal really needs generalizing as you have proposed. In my own production code I use a variant of this post I made years ago. https://gist.github.com/bradphelan/5395652 I used I even have code for immutable updates of objects within immutable collections just not in the gist as posted. A native solution for this would be great.
|
Beta Was this translation helpful? Give feedback.
-
See #162 for the champion issue most closely related to this discussion. I've linked this disucssion from there. |
Beta Was this translation helpful? Give feedback.
-
I believe this thread is similar to what I was looking for in the issue [Question/Proposal] Immutable Parent Child API. I was initially comparing an immutable parent/child scenario similar to what the team did in Roslyn with SyntaxTrees and SyntaxNodes. Let's use the infamous Person class. A Person object can have zero, one or more children (which are also Person objects) and its children can have zero, one or more children (Descendants; also Person objects), etc., etc. The Person object can also have a Parent (Person object) and going up the tree, can have zero, one or more Ancestors (also Person objects). So going back to the comparison with Roslyn, SyntaxNodes are updated and returned with the changes. In addition, the Parent and SyntaxTree are updated respectfully (or at least in a manner to lazily query for them when needed). I get the basics of updating properties like WithFirstName(FirstName: "Bobby"). However, what if you wanted to replace a specific descendant person, similar to using SyntaxNode ReplaceNode method? // This code is not exact, just trying to explain a little further.
Person granddad = new Person(// with a child; c1 and a couple grandchildren; gc1, gc2);
Person grandchild2 = granddad.Children[0].Children[1]; // Get gc2 from c1.
var gd = grandchild2.Parent.Parent; // granddad and gd should be equivalent.
Person gc3 = new Person(// with properties); // Create a new grandchild person.
var gdUpdated = granddad.ReplacePerson(grandchild2, gc3); // Removed gc2 and replaced with gc3.
// At this point, gdUpdated would look like the following...
// gcUpdated
// c1
// gc1
// gc3
// In addition, I didn't specify anything about granddad when instantiating grandchild gc3.
// However, a relative connection would be made when replacing the grandchildren.
// Meaning, finding the granddad below would be similar to finding above.
Person grandchild3 = granddad.Children[0].Children[1]; // Get gc3 from c1.
gd = grandchild3.Parent.Parent; // granddad and gd should be equivalent. So my question is... how could/would you be able to do something similar using Records or Immutable Types and what is being discussed in related proposal(s)? Any help is appreciated. Updated: I noticed they mentioned Roslyn SyntaxTrees as a use-case for Records in the C# Design Meeting 2015-03-25 |
Beta Was this translation helpful? Give feedback.
-
This would sure that with syntax more compelling. However, it would require more expected convention on the part of immutable types. The current proposal only requires the type getting the with syntax to have a With method with all the corresponding parameters. This proposal would require the compiler to understand things like collections have WithElement and possibly others. Maybe that's not so bad. |
Beta Was this translation helpful? Give feedback.
-
@mattwar indexed immutable collections in |
Beta Was this translation helpful? Give feedback.
-
@orthoxerox its not so much that existing libraries have conventions or even agree, its that the language with have to bless one of the patterns. |
Beta Was this translation helpful? Give feedback.
-
Maybe it's not so bad that one pattern will have to be chosen. |
Beta Was this translation helpful? Give feedback.
-
Note that With
Hope this helps |
Beta Was this translation helpful? Give feedback.
-
Instead of WithElements perhaps we could use |
Beta Was this translation helpful? Give feedback.
-
I love this proposal! It would be a great quality-of-life improvement for me. @orthoxerox What do you think about making the old value available so that non-with operations can be nested? For example: state = state with { PerCompany.State.LineItems.Rows = Rows.Remove(lineItem) } The names in scope would be |
Beta Was this translation helpful? Give feedback.
-
Seems you find a way to do nested withers that you like but I want to bring up a concept from FP world which is called lenses. I have a somewhat rudimentary understanding of the math behind lenses but I think I got the concepts so I am taking a risk describing it here :). Lenses allows focusing on properties in a nested structure and perform an "immutable update" of them. A rudimentary lens for .NET could look like this interface Lens<T, P>
{
P Get(T t);
T Set(T t, P p);
} Often one define a few side of combinator functions for lenses but there's also usually some kind of code-generation to generate lenses for known types. As we are here inside a compiler it could be possible to create that on the fly. // Vague proposal of lens construction syntax
Lens<MyClass, int> l = $MyClass.MyProperty.MyNestedProperty;
MyClass myUpdatedInstance = l.Set(myInstance, 2); Lenses have applications outside just creation of objects such as if you want to have functions that operator on specific properties of a nested immutable structure. For example if I define a textbox that on updates should read and updates it's values from a nested property it could be like this TextBox<T> CreateTextBox<T, P>(string label, Lens<T, P> lens); Reading the previous issues a bit more closely I think this idea resembles the suggestion by @bradphelan somewhat. |
Beta Was this translation helpful? Give feedback.
-
@mrange you can see some work toward lenses here https://stackoverflow.com/questions/68012124/record-lenses-expression-tree-for-with-expression |
Beta Was this translation helpful? Give feedback.
-
As mentioned in one of the LDM notes,
with
syntax doesn't really pay for itself, since it's almost tasteless syntactic sugar overWith
methods. I want to restart the discussion from dotnet/roslyn#16459 in the new repo:The withers should be nestable and transform compound assignment, like this example below, this makes them much more useful than bare
With
methods:More details
with
should accept nested immutable values:with
should accept compound assignment operators:with
should work with immutable collections (they probably should support something likeWithElement
(AddOrUpdate
?)):Now we can see how the examples will be transformed by the compiler:
Let's say we have the following immutable records:
e.g.:
Grammar
Beta Was this translation helpful? Give feedback.
All reactions