Change SoyValue to be an abstract base class instead of an interface.
Merge many Abstract* classes into their interfaces which have now been made abstract. Mark as many methods final as possible.
The goal here is to:
Improve method dispatch performance, invokevirtual is easier than invokeinterface for the VM and final methods are even easier to reason about (but you cannot mark interface methods final)
simplify the type hierarchies by simply reducing the number of classes.
e.g. we don't need SoyListAbstractSoyList and ListBackedList we can get away with just SoyList 🎉
The trickiest part of this is the multiple inheritance in the collection hierarchies. Before we had SoyMapSoyRecord and SoyLegacyObjectMap as parallel interfaces. Many of the implementations like DictImpl or SoyMapData implemented all 3, some like SoyMapImpl or SoyRecordImpl implemented only 1. To fit everything into the singly-rooted hierarchy we had to pick a hierarchy across these 3. I decided on....
The reason I selected this relationship was due to prior art for SoyProtoValue, and this also seemed to be mostly compatible with the Js object system. if SoyLegacyObjectMap is just Object<string,?> then SoyRecord is some concrete struct (which can always be upcast to object), and SoyMap is an es2015 Map which is a very special kind of object.
The main alternative I considered was changing many methods to be static. This is a much larger breaking change, and at least my attempt ended up being a regression. AFAICT, The reason why is because static -> virtual -> static is worse than virtual -> static. So the only really good usecase for making things static is if they don't need to call a virtual method, if they do then we are inhibiting the JITs ability to understand that virtual call. Making a method final is just as valuable and far more compatible so this approach ends up being simpler.
Changing the type hierachy is risky, so i spent some time auditing various instanceof tests on the SoyLegacyObjectMap and SoyRecord interfaces to see if there might be latent issues and these are thankfully quite rare and seem fine.
Change SoyValue to be an
abstract
base class instead of aninterface
.Merge many
Abstract*
classes into their interfaces which have now been madeabstract
. Mark as many methodsfinal
as possible.The goal here is to:
invokevirtual
is easier thaninvokeinterface
for the VM andfinal
methods are even easier to reason about (but you cannot markinterface
methodsfinal
)SoyList
AbstractSoyList
andListBackedList
we can get away with justSoyList
🎉The trickiest part of this is the multiple inheritance in the collection hierarchies. Before we had
SoyMap
SoyRecord
andSoyLegacyObjectMap
as parallel interfaces. Many of the implementations likeDictImpl
orSoyMapData
implemented all 3, some likeSoyMapImpl
orSoyRecordImpl
implemented only 1. To fit everything into the singly-rooted hierarchy we had to pick a hierarchy across these 3. I decided on....SoyMap
extendsSoyRecord
extendsSoyLegacyObjectMap
The reason I selected this relationship was due to prior art for
SoyProtoValue
, and this also seemed to be mostly compatible with the Js object system. ifSoyLegacyObjectMap
is justObject<string,?>
thenSoyRecord
is some concrete struct (which can always be upcast to object), andSoyMap
is an es2015Map
which is a very special kind of object.The main alternative I considered was changing many methods to be
static
. This is a much larger breaking change, and at least my attempt ended up being a regression. AFAICT, The reason why is becausestatic
->virtual
->static
is worse thanvirtual
->static
. So the only really good usecase for making thingsstatic
is if they don't need to call avirtual
method, if they do then we are inhibiting the JITs ability to understand that virtual call. Making a methodfinal
is just as valuable and far more compatible so this approach ends up being simpler.Changing the type hierachy is risky, so i spent some time auditing various
instanceof
tests on theSoyLegacyObjectMap
andSoyRecord
interfaces to see if there might be latent issues and these are thankfully quite rare and seem fine.