Repository navigation
Description
This is a tracking issue for adding a ScalarValue::Array(ArrayRef) variant to vortex-array/src/scalar, replacing the per-row Vec<Option<ScalarValue>> representation for List and FixedSizeList scalars.
This supersedes #6771 and revives the abandoned work in #6717.
Motivation
In the past, scalars used to live in a vortex-scalar crate, and vortex-array depended on vortex-scalar. This prevented us from adding an ArrayRef variant to ScalarValue since that would have caused a dependency cycle.
In #6523, we moved the entire vortex-scalar crate into a submodule of vortex-array. So we now have the ability to do this.
There are several benefits to having an Array variant in our scalars:
- The main benefit is that working with
List,ListView, andFixedSizeListscalars becomes much more performant as we do not need to unwrap each row value into anOption<ScalarValue>- Given that there are important extension types that deal with these list types (
Uuid,Vector, tensors in general)
- Given that there are important extension types that deal with these list types (
INlist predicates are very slow in Vortex- There are many potential
Constantoptimizations for constantListarrays, and working with a slice of anArrayRefin theScalarValueis much more performant - TODO are there other things? Likely related to
ConstantArrayandSparseArray?
Design
vortex-array/src/scalar/scalar_value.rs
pub enum ScalarValue {
// ...
Tuple(Vec<Option<ScalarValue>>), // Struct scalars
Array(ArrayRef), // NEW! List + FixedSizeList scalars
Variant(Box<Scalar>),
}vortex-proto/proto/scalar.proto
message ScalarValue {
oneof kind {
// ... (existing tags 1..11)
StructValue struct_value = 9; // renamed from ListValue
ArrayValue array_value = 12; // NEW!
}
}
// TODO is this enough?
message ArrayValue {
uint64 row_count = 1;
repeated string encoding_ids = 2; // self-describing; no shared ArrayContext
bytes data = 3; // ArrayRef::serialize output
}IMPORTANT TODO!!!
We might need to enforce that the inner ArrayRef is recursively canonicalized at construction so that Hash/PartialEq/Display/unpack_native stay session-free. Constructors might need to also add &VortexSession. For backcompat, a StructValue payload paired with a List DType materializes as ScalarValue::Array.
I think this is the main blocker, but it is unclear if this is the only one...
Steps
TBD, probably want to break this down into more steps?
- Add
ScalarValue::Array, renameList->Struct, route list/FSL scalars throughArray. - Proto changes (
StructValuerename, newArrayValuetag 12, backcompat read path). - Thread
&VortexSessionthrough scalar constructors andto_protoso we can callArrayRef::serialize(ctx, session, options)and recursively canonicalize. - Restore
Uuid::unpack_nativeand thevortex-tensorconstant test helpers disabled inScalarValue::Array#6717. - Update external call sites (
vortex-datafusion,vortex-duckdb,vortex-python,vortex-ipc,parquet-variant,sequence::list_contains).
Unresolved questions
- Do we need to canonicalize the inner
ArrayRefrecursively at construction, or keep it lazy? - Does
ExtVTable::unpack_nativeneed to add a&VortexSession/&mut ExecutionCtxparameter? - Do we really need to be able to
Hashall of our scalar and scalar views? - Does the
ScalarFnVTable::Optionsreally need theEqandHashbounds? Things likeScalarFnRefandExpressionrely on that for optimization and rule matching.
Implementation history
- Semi-related: Fix
Scalarde/serialization with proto and outline nulls fromScalarValue#6309 ScalarValue::Array#6717 (closed and stale)- Rename
ScalarValue::ListtoScalarValue::Tuple#7672 - TODO
Activity
robert3005 commentedon Apr 28, 2026
I think you either entirely deprecate non primitive scalarvalues and require them to be arrays or we allow them to be either a value or an array
connortsui20 commentedon Apr 28, 2026
@robert3005 so you think we should deprecate the 2 string variants? I think there is value in having the struct
Tuplevariant as well asVariantas a separate scalar value type, but I guess the string types fall into a similar category as theListtypes.I think that given we definitely want this for
Lists, this tracking issue can focus on just addingScalarValue::Arrayfor the list types, and then once that is actually working we can decide on if we want to also move the string scalars over toScalarValue::ArrayRemove `PartialOrd` implementation for `ScalarValue` (#7742)