Yes, for fixed-length inner types, the proposed serialization matches the one of List<T,1>
.
However, for variable-length T
, List<T,1>
emits an offset-entry, which is not necessary in the optional case as the length can be implied from the full list length - if it is serialized as b""
, it is None
, otherwise it is Some(T)
.
For merkleization, Optional[T]
, List<T,1>
and Union<T,1>
are all the same, with same hash_tree_root
. Only serialization is affected.
Conceptually, an Optional
type (however it is serialized / merkleized) is a useful concept (see EIP-4844 and the Verkle effort). It makes it clear to the reader what is meant. With List<T, 1>
it needs to be accessed like an array, and with Union<None, T>
it is unclear whether the intent is for this to grow to a Union<None, T, U>
in the future. At the very least, it should be defined as a typealias and recommended for use by the protocol, so that the underlying intent can be appropriately represented in higher-level languages (e.g., Swift ?.
/ !.
, C# ??
, Nim valueOr
and so on).
If there is a need for nested Optional[Optional[...]]
, or Optional[List[T, N]]
(note that empty lists usually already represent optional), the Union
serialization could help disambiguate between None
and Some(None)
/ Some(List[T, N]())
. If those constructs are not needed, the proposed format based on @zah 's suggestion is a bit more compact, and gets rid of the parsing complexity of “what if someone sends an unknown selector”. In any case, for unions as well as optionals, the None
branch could be serialized as b""
instead of b"\0"
without loss of generality (so, only the Some
branch would have a prefix).
Ultimately, point being, what is needed for new features are Optionals, not Unions, at this time.