<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    Hi David,<br>
    <br>
    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.<br>
    <br>
    Thanks,<br>
    Vicente<br>
    <br>
    [1]
    <a class="moz-txt-link-freetext" href="https://mail.openjdk.org/pipermail/amber-dev/2020-April/005900.html">https://mail.openjdk.org/pipermail/amber-dev/2020-April/005900.html</a><br>
    [2]
    <a class="moz-txt-link-freetext" href="https://mail.openjdk.org/pipermail/amber-dev/2020-May/005972.html">https://mail.openjdk.org/pipermail/amber-dev/2020-May/005972.html</a><br>
    <br>
    <div class="moz-cite-prefix">On 6/30/23 18:28, David Alayachew
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAA9v-_PaRmqJY1mZib2ZGnhsFr8LJg5vHAZaCAoZKjTjg+cVFQ@mail.gmail.com">
      
      <div dir="ltr">
        <div style="font-family:monospace" class="gmail_default">Hello
          all,<br>
          <br>
          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.</div>
        <div style="font-family:monospace" class="gmail_default"><br>
        </div>
        <div style="font-family:monospace" class="gmail_default">---<br>
        </div>
        <div style="font-family:monospace" class="gmail_default"><br>
        </div>
        <div style="font-family:monospace" class="gmail_default">For the
          past couple of weeks, I have been building a program that uses
          a State Transition Diagram (aka State Machine, Finite
          Automata, etc. -- <a href="https://en.wikipedia.org/wiki/Finite-state_machine" moz-do-not-send="true" class="moz-txt-link-freetext">https://en.wikipedia.org/wiki/Finite-state_machine</a>)
          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.<br>
          <br>
          Here is a(n EXTREMELY) simplified version of my actual
          problem. Imagine I have code like the following.<br>
          <br>
          ```java<br>
          <br>
          sealed interface Node<T> permits StartNode,
          BranchingNode, EndNode {...unrelated stuff here...}<br>
          <br>
          record StartNode<T> (Node<T> a, Node<T> b,
          Node<T> c) implements Node<T> {}<br>
          record BranchingNode<T> (Node<T> a, Node<T>
          b, Node<T> c, ...fields unrelated to transitioning...)
          implements Node<T> {}<br>
          record EndNode<T> (...fields unrelated to
          transitioning...) implements Node<T> {}<br>
          <br>
          ```<br>
          <br>
          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.<br>
          <br>
          Things worked out well enough until I tried to model a
          circular relationship.<br>
          <br>
          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.<br>
          <br>
          For example, assume that my State Transition Diagram is as so.<br>
          <br>
          S ---a---> T<br>
          S ---b---> U<br>
          S ---c---> V<br>
          T ---a---> U<br>
          T ---b---> V<br>
          T ---c---> E<br>
          U ---a---> V<br>
          U --b|c--> E<br>
          V -a|b|c-> E<br>
          <br>
          S is my StartNode, and E is my ExitNode.<br>
          <br>
          In this case, modeling with records is easy. It would look
          like so.<br>
          <br>
          ```java<br>
          <br>
          ExitNode<UnrelatedStuff> e = new
          ExitNode<>(...unrelated...);<br>
          BranchingNode<UnrelatedStuff> v = new
          BranchingNode<>(e, e, e, ...unrelated...);<br>
          BranchingNode<UnrelatedStuff> u = new
          BranchingNode<>(v, e, e, ...unrelated...);<br>
          BranchingNode<UnrelatedStuff> t = new
          BranchingNode<>(u, v, e, ...unrelated...);<br>
          StartNode<UnrelatedStuff> s = new StartNode<>(t,
          u, v);<br>
          <br>
          return s;<br>
          <br>
          ```<br>
          <br>
          But once I hit a circular reference, I could not figure out
          how to model the code using the same format.<br>
          <br>
          For example, what if I say the following instead?<br>
          <br>
          V ---a---> T<br>
          <br>
          How do I model that using my current representation?<br>
          <br>
          Obviously, I could change my representation, but all of them
          required me to "taint" my representation in incorrect ways.<br>
          <br>
          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.<br>
          <br>
          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.<br>
          <br>
          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!<br>
          <br>
          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.<br>
          <br>
          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.<br>
          <br>
          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.<br>
          <br>
          ```java<br>
          <br>
          enum State<br>
          {<br>
          <br>
          V(T, EXIT, EXIT), //FAILURE -- T cannot be referenced yet<br>
          U(V, EXIT, EXIT),<br>
          T(U, V, EXIT),<br>
          ;<br>
          <br>
          ...public final fields and constructor...<br>
          <br>
          }<br>
          <br>
          ```<br>
          <br>
          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.<br>
          <br>
          It reminded me of that one programming meme.<br>
          <br>
          > * High Quality<br>
          > * Quickly Built<br>
          > * Low Cost<br>
          > <br>
          > You can only pick 2<br>
          <br>
          But instead, it's<br>
          <br>
          * Circular Relationship<br>
          * Immutability<br>
          * Direct References<br>
          <br>
          What are your thoughts? Is this a problem in your eyes too? Or
          simply a non-issue?<br>
          <br>
          Thank you for your time and insight!<br>
          David Alayachew<br>
        </div>
      </div>
    </blockquote>
    <br>
  </body>
</html>