P.S. If the original designers of Java bytecode had allowed <init> to allocate its own object, and return it, we’d be having a different discussion. I wish it had been like that. I think it is a false economy to have “new X(…)” and “super(…)” call the same method symbol; that is the root of many evils.
On 13 Jul 2023, at 13:52, John Rose wrote: > On 13 Jul 2023, at 7:24, Brian Goetz wrote: > >> This is a good thought; we split the initialization protocol and its a fair >> question to ask whether we can go back to a lump. >> >> In this case, I suspect John is about to say “Please let’s not give the >> verifier any more jobs to do.” > > It is that, and even worse. If you work the details, you’ll quickly run into > the fact that the <init> protocol (for Java constructors) builds an object > but does not return the new object, it takes the new object from the caller > in a tabula rasa (blank) state, and pokes values into it. Worse, the new > object is supplied (by a new opcode) from an untrusted (even hostile) client. > That means that the verifier needs complex rules (>10% of the total > complexity) to track these untrusted-but-trusted blank objects and make sure > they are handed to <init> before being used. That’s bad. We have a steady > bug stream from this very delicate machinery. Maybe it’s done after a > quarter century but I wouldn’t bet the farm on that. > > Worse still, for values, there is no architecturally defined state, for > values, which corresponds to the “tabula rasa” state of the receiver of an > <init> call. We know something of that state; it is called a “larval > object”, but the Valhalla JVMS does not define or rely on it. The proposed > “unification” would require us to somehow simulate larval objects in terms of > today’s blank identity objects, and define how the larval-to-adult state > transition works, or it would have to build new verifier rules for larval > objects (mutable while <init> runs, then pure values after that). Either > option seems much worse than what we have chosen to do so far. > > What we have chosen to do so far is have a functionally clean model for value > objects that does not require mutability, either temporary (larval-only) or > permanent (I shudder at that thought). This functionally clean model uses > withfield instead of getfield, and aconst_init instead of the “new” opcode. > I think that is a great trade, because it lets us off the hook from defining > mutability into values, at any stage of their lifetimes. > > Yes, serialization smuggles larval mutability back in, but that’s a private > matter of optimization, between the VM and JDK. I really don’t want to see > that in the JVMS, because it would be just as hairy and complex and bug-prone > as today’s new/<init> dance. Yes, we should use the old mechanisms when we > can, and we do! But the new/<init> dance is, IMO, hopelessly entangled with > a presupposition of object identity, and also hopelessly buggy; so I don’t > think it can help us, and I wouldn’t touch to extend it even if I thought it > might help. > > How’s that? :-)
