<div dir="auto"><div>I see you though of it as a compile time thing. But like you also mentioned it would be difficult for the compiler to prove that no access occurs before initialization severely limiting the usefulness. Also the things with for example instanceof and synchronization are real questions as they primary operate on identity and don't use the (garbage) data of a half initialized object.<div dir="auto">Like:</div><div dir="auto">Foo foo = __uninitialized;</div><div dir="auto">boolean b = foo instanceof Foo //true or false </div><div dir="auto">syncronized(foo) { //works or not? </div><div dir="auto"><br></div><div dir="auto">} </div><div dir="auto">foo = new Foo();</div><div dir="auto"><br></div><div dir="auto"><br></div>Also in terms of value objects and primitives it doesn't really work at all since they by definition do not have identity (in Java) so since they cannot be referenced at all they can't ever be in this uninitialized state. </div><div dir="auto">Overall cyclical REFERENCE structures don't make sense or work in datatypes without identity. </div><div dir="auto"><br></div><div dir="auto">The only big obstacle I see is that it's probably not worth the cost of implementating. The private field or id approach both work and solve the problem hence this is merely a convenience feature, even though the concept might allow unforeseen possibilities not obvious right now. If other problems are found that would be solved with it it might become viable to implement. </div><div dir="auto"><br></div><div dir="auto">Great regards </div><div dir="auto">RedIODev <br><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Thu, Jul 6, 2023, 20:27 David Alayachew <<a href="mailto:davidalayachew@gmail.com">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div style="font-family:monospace" class="gmail_default"><br>Hello RedIODev,<br><br>Thank you for your response! And thank you for your patience, the holidays took up a lot of time.<br><br>Let me preface this by saying that I won't have many (if any) satisfying answers for you. A lot of these details seem to go deep into the guts about how the JVM work, and while I am happy to learn if you can point me to some resources, the fact is, I just don't have that information in my head at the moment.<br><br>Regardless, I'll attempt each of your bullets.<br><br>> I think the biggest problems would be<br>> <br>> 1. How do you mark a memory location as allocated (has<br>>    identity aka memory address) but should still be<br>>    treated as null which changes later without any<br>>    notice? It's like a reverse WeakReference<br><br>Not sure.<br><br>To explain the (very nebulous/shapeless) concept I had in my head, here it goes.<br><br>I believe that the concept of a circular reference is an inherently identity-based operation. Therefore, we must exclude primitives and value classes from the equation.<br><br>Next, I am of the assumption that there exists a point in time where memory has been allocated, but the data has not been written to memory yet. My hope and prayer was that we could allow actions to occur between those specific 2 actions safely by allowing the compiler to "prove" that the allocation AND memory write will eventually happen before any dereferencing occurs.<br><br>As a result of that, you have an address that you can pass around to other variables, but they are not permitted to dereference it until it is actually initialized with data -- aka, the memory write.<br><br>Based on this ethereal concept, I don't know that the data needs to be marked in any way at all. We were taking 2 actions that were essentially contiguous, and breaking them up so that subsequent "safe" actions could occur in between the 2.<br><br>Please let me know if I am wildly off of the mark here.<br><br>> 2. How would you represent it syntactically it's neither<br>>    null nor a valid object it's a in between state<br>>    previously unknown.<br><br>Truthfully, I don't really care much about what the syntactic representation looks like as long as it is immediately clear and obvious.<br><br>The semantics, however, are a little different.<br><br>I would treat whatever syntactic choice we use as a sort of "hall pass" for definite assignment. Basically, we have the variable uninitialized as usual, but then areas where we want to do an illegal forward reference, we put our "hall pass" in front of the variable to signify that it is "safe to use uninitialized".<br><br>For example.<br><br>class Node<br>{<br><br>    final Node next;<br><br>    Node(Node next)<br>    {<br>        this.next = next; //no dereferencing has occurred for the entirety of this constructor, and thus, it is "safe".<br>    }<br><br>}<br><br>final Node rock, paper, scissors;<br><br>rock = new Node(__uninit scissors); //the "hall pass", which triggers the scissors memory location to be allocated<br>paper = new Node(rock);<br>scissors = new Node(paper); //the scissors memory allocation is now being written to, completing initialization<br><br>> 3. There would be many changes in the language necessary<br>>    to make this feature work reliably and the use beyond<br>>    niece things like circular references in immutable<br>>    datastructures are probably low.<br><br>Frankly, the primary reason why I feel this feature should exist is for clarity's sake. We are allowing an object to represent a relationship more directly. If a references b and b references a, then just bootstrap them into each other and be done with it! Introducing indirection, mutability, reflection, or piles of builder code boilerplate when what is needed is a direct relationship sounds to me like sidestepping a problem by using Java's other strengths and points of flexibility. And while that strength and flexibility is both useful and powerful, it adds overhead that makes problems harder and harder to reason about. I think removing all of that is making coding simpler, and that is a goal worth pursuing imo.<br><br>> 4. This would also bring up many questions in which cases<br>>    the memory behaves like a object and in which case<br>>    null. Like synchronization, null checks, instanceof,<br>>    etc.<br>> <br>> It's likely not worth the complexity and the cost. <br><br><br>Ideally, this should not add any new runtime features, but instead, should be separating pre-existing features into separate actions. My hope is that this can be an "unsafe" operation that can be proven "safe" by the compiler.<br><br>And yes, there is a limit to what the compiler can prove. For example, if the "constructor" in the example was actually a method on an interface, well we don't know what the implementing method does. Maybe the implementing method dereferences the variable, which then begs the question of what failure should look like.</div><div style="font-family:monospace" class="gmail_default"><br></div><div style="font-family:monospace" class="gmail_default">I am of the mindset that we should treat failure the same way that we do in the nonatomic concept from Valhalla and mark that as a cost developers can opt into to get the tradeoffs they want.<br><br>As for what should literally happen during failure, well based on what I described, you can end up with an object containing garbage data. Of course, the compiler can protect you from a vast majority of these problems, but you opt into getting garbage data back if you use this feature incorrectly.<br><br>Please let me know your thoughts.<br><br>Thank you for your time and questions!<br>David Alayachew<br></div><br></div>
</blockquote></div></div></div>