Question about circular references
Vicente Romero
vicente.romero at oracle.com
Mon Jul 3 16:06:40 UTC 2023
Hi David,
The question about record's mutability has been asked several times
actually in this same list there are some previous ones asking for this
same issue. As a reference there is a very interesting one covering this
one an other issues related to records [1] and please see Brian's answer
[2] which as mentioned covers not only mutability but other topics too.
Thanks,
Vicente
[1] https://mail.openjdk.org/pipermail/amber-dev/2020-April/005900.html
[2] https://mail.openjdk.org/pipermail/amber-dev/2020-May/005972.html
On 6/30/23 18:28, David Alayachew wrote:
> Hello all,
>
> First off, please let me know if I have CC'd the wrong groups. I've
> CC'd the Amber Dev Team since this involves records, but it's not
> specifically about records.
>
> ---
>
> For the past couple of weeks, I have been building a program that uses
> a State Transition Diagram (aka State Machine, Finite Automata, etc.
> -- https://en.wikipedia.org/wiki/Finite-state_machine) to model part
> of its control flow. I've been using some Amber features to facilitate
> this (and having a wonderful time of it), but then I hit a snag.
>
> Here is a(n EXTREMELY) simplified version of my actual problem.
> Imagine I have code like the following.
>
> ```java
>
> sealed interface Node<T> permits StartNode, BranchingNode, EndNode
> {...unrelated stuff here...}
>
> record StartNode<T> (Node<T> a, Node<T> b, Node<T> c) implements
> Node<T> {}
> record BranchingNode<T> (Node<T> a, Node<T> b, Node<T> c, ...fields
> unrelated to transitioning...) implements Node<T> {}
> record EndNode<T> (...fields unrelated to transitioning...) implements
> Node<T> {}
>
> ```
>
> This type hierarchy is meant to represent a control flow of sorts.
> Control flow is (imo) best modeled using a State Transition Diagram,
> so I instinctively reached for that. And since my API needed to be
> nothing but the data (each Node needed to be tightly coupled to my
> internal state representation), I realized that this is an ideal use
> case for records.
>
> Things worked out well enough until I tried to model a circular
> relationship.
>
> Through chance, all of my control flows up to this point were
> tree-like, so I could model them by starting from the "leaves," then
> climbing up until I got to the "roots". To use State Transition
> Diagram terminology, I started from my exit states and modeled my way
> up to my entry states.
>
> For example, assume that my State Transition Diagram is as so.
>
> S ---a---> T
> S ---b---> U
> S ---c---> V
> T ---a---> U
> T ---b---> V
> T ---c---> E
> U ---a---> V
> U --b|c--> E
> V -a|b|c-> E
>
> S is my StartNode, and E is my ExitNode.
>
> In this case, modeling with records is easy. It would look like so.
>
> ```java
>
> ExitNode<UnrelatedStuff> e = new ExitNode<>(...unrelated...);
> BranchingNode<UnrelatedStuff> v = new BranchingNode<>(e, e, e,
> ...unrelated...);
> BranchingNode<UnrelatedStuff> u = new BranchingNode<>(v, e, e,
> ...unrelated...);
> BranchingNode<UnrelatedStuff> t = new BranchingNode<>(u, v, e,
> ...unrelated...);
> StartNode<UnrelatedStuff> s = new StartNode<>(t, u, v);
>
> return s;
>
> ```
>
> But once I hit a circular reference, I could not figure out how to
> model the code using the same format.
>
> For example, what if I say the following instead?
>
> V ---a---> T
>
> How do I model that using my current representation?
>
> Obviously, I could change my representation, but all of them required
> me to "taint" my representation in incorrect ways.
>
> For example, I could swap out my records for simple classes where the
> references to Node's were mutable. But I strongly disapprove of this
> strategy because these nodes do NOT have a mutable relationship.
> Obviously, I could put something in the Javadoc, but I want to fix the
> incorrect representation, not put a warning sign in front of it.
>
> Also, I could use indirection, like having a separate Map whose values
> are the actual Node references and the keys would be a record
> Pair<T>(String nodeId, Branch branch) {} where Branch is enum Branch {
> a, b, c, ; } and then give each Node an id, changing my record to now
> be record BranchingNode<T> (String id, ...the same as above...) {}.
> But ignoring the fact that I now have to deal with managing an id,
> I've also added a lot of unnecessary bloat and indirection just to get
> the circular reference I wanted. What should be a direct relationship
> now requires a Map lookup.
>
> In that same vein, someone suggested that I use pattern-matching for
> switch, but that would require me to create a new switch expression
> for every single state. That's even more verbose and indirect than the
> Map. At least with the map, I can put them all in one expression. This
> strategy has an expression for each state!
>
> I've been told that there is another pathway involving reflection, but
> it basically amounts to breaking the rules of Java. Apparently, you
> can turn off finality to insert in fields you want, and then turn it
> back on? I liked this idea the least compared to all of the others, so
> I didn't pursue it any further.
>
> In the end, I decided to go down the Map lookup route. But I just
> wanted to point out my experience with this because it was a
> surprising and annoying speed bump along an otherwise smooth road. I
> didn't think that something as small as a circular reference would
> require me to uproot my entire solution.
>
> And finally, I want to emphasize that the same blockers above apply no
> matter what pathway I go down. I had actually tried implementing this
> first as an enum before I tried a record, since an enum would more
> accurately represent my state.
>
> ```java
>
> enum State
> {
>
> V(T, EXIT, EXIT), //FAILURE -- T cannot be referenced yet
> U(V, EXIT, EXIT),
> T(U, V, EXIT),
> ;
>
> ...public final fields and constructor...
>
> }
>
> ```
>
> But even then, the same problem occurred -- I can't reference an enum
> value until it has been declared. I thought going down the path of
> records would give me the flexibility I wanted, but no dice.
>
> It reminded me of that one programming meme.
>
> > * High Quality
> > * Quickly Built
> > * Low Cost
> >
> > You can only pick 2
>
> But instead, it's
>
> * Circular Relationship
> * Immutability
> * Direct References
>
> What are your thoughts? Is this a problem in your eyes too? Or simply
> a non-issue?
>
> Thank you for your time and insight!
> David Alayachew
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230703/9617432f/attachment-0001.htm>
More information about the amber-dev
mailing list