<div dir="ltr"><div style="font-family:monospace" class="gmail_default"><br>Hello Ron,<br><br>Thank you for your response!<br><br>> > But regardless, you are declaring this out of the blue.<br>> > Where are you coming from when you say this? What backs<br>> > this statement up? I have come to you with widely<br>> > accepted definitions. If you are going to say that final<br>> > fields, in this instance, don't permit cycles, I need you<br>> > to explain how and why, not just claim that they do.<br>> <br>> For the purpose of this discussion, final is a feature<br>> that requires a field to be assigned (only once) in the<br>> constructor. If it’s assigned a value arriving to the<br>> constructor from the outside, then that value cannot the<br>> object currently being constructed. (Yes, you can get<br>> around that by passing `this` from a constructor to other<br>> constructors). This is in contrast to non-final fields<br>> that can be assigned outside the constructor, and so can<br>> be assigned in methods that receive the current object<br>> itself as an argument, something that the constructor<br>> cannot do.<br><br>Ok, I think I see where the problem is.<br><br>When you say "final fields do not PERMIT cycles", I am interpreting that to mean "whether or not cycles are representable, they are not permitted, and this is by intention". Whereas I think you are saying "final fields are unable to have cycles because pre-existing mechanics prevent it, even though there is nothing explicitly forbidding it with intention".<br><br>If that is the case, then we have been talking past each other.<br><br>My entire point thus far has been acknowledging that, yes, these things are not representable, but then saying that they in fact should be. You have been retorting the entire time saying they are not representable and that's not a problem because of (what I perceive to be) circular logic. You have still not responded to those points I've made by the way.<br><br>But to actually address this quote, yes, as I have said multiple times, whether it is through records or final fields or something else entirely, we are currently unable to represent cycles. But that is a byproduct of the particular set of mechanics Java provided to create records and finality. At no point along the line was it said that final SHOULD NOT be able to represent circular references. And it is THAT that I am asking for evidence for. And the reason why is because, if there is not an explicit, intentional reason why they should not, then I am of the firm opinion that they should be able to.<br><br>> > By all means, I am not picky. Can you show me what this<br>> > would look like though? I can understand how you would<br>> > achieve immutability doing this, but not the directness<br>> > constraint I am talking about above.<br>> <br>> You create your nodes and then you set their references<br>> (say, from a builder class), but you don’t expose a<br>> public API that allows mutating your nodes.<br><br>So, in short, you are saying that I should be creating a builder class, or some privately available mechanism, to be able to insert in the necessary references while still keeping my public API with no mutation options?</div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">Here's a compilable example.</div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">```java</div><div style="font-family:monospace" class="gmail_default"><br>public class ImmutableAndDirectCircularReferences<br>{<br><br> public static class GraphBuilder<br> {<br> <br> public static Node graph1()<br> {<br> <br> Node start = new Node();<br> Node t = new Node();<br> Node u = new Node();<br> Node v = new Node();<br> Node end = new Node();<br> <br> start.setter(t, u, v);<br> t.setter(u, v, end);<br> u.setter(v, end, end);<br> v.setter(end, end, end);<br> end.setter(end, end, end); //or something like this<br> <br> return start;<br> <br> }<br> <br> }<br><br> public static class Node<br> {<br> <br> private Node t, u, v;<br> <br> private Node() {}<br> <br> private void setter(Node t, Node u, Node v)<br> {<br> <br> this.t = t;<br> this.u = u;<br> this.v = v;<br> <br> }<br> <br> public Node t()<br> {<br> <br> return this.t;<br> <br> }<br> <br> public Node u()<br> {<br> <br> return this.u;<br> <br> }<br> <br> public Node v()<br> {<br> <br> return this.v;<br> <br> }<br> <br> //equals, hash, tostring<br> <br> }<br><br>}<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">Fair. I'll concede that it checks all the boxes. More specifically,
I'll concede that it is not accurate for me to say that Java can't model
circular references while maintaining immutability and direct
references.</div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">But man, it does it in the worst way possible. We have more boilerplate than multiple other solutions combined, and even then, we have to go deep into indirection to EVENTUALLY construct a direct solution. It's the worst of both worlds while still checking all the boxes. Knowing that this is the actual solution to my problem makes me wish for another solution that much more.<br></div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">But regardless. Point conceded.</div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">Thank you for your time and help!<br>David Alayachew<br></div><br></div>