Skip to content

Track lazy indexed array abstraction #816

@He-Pin

Description

@He-Pin

Summary

Track a dedicated sjsonnet lazy indexed array abstraction.

The motivation is similar to what Scala LazyList gives for sequential collections: avoid building intermediate thunks or fully materialized intermediate data when a pipeline can remain lazy. Jsonnet arrays, however, need stronger indexed semantics than LazyList: cheap length, random access by index, reverse/slice/repeat/concat behavior, and predictable materialization.

This issue is for designing and implementing a Jsonnet-specific lazy indexed array layer rather than spreading ad hoc lazy/thunk logic across individual stdlib functions.

Motivation

Today many stdlib producers and consumers still exchange Array[Eval] or allocate per-element thunks such as LazyApply1. That works, but it can create large intermediate arrays of wrappers even when the next operation only indexes, folds, joins, renders, or partially consumes the data.

A dedicated lazy indexed array abstraction could make these paths explicit:

  • std.map / std.mapWithIndex / std.makeArray
  • std.slice
  • std.repeat
  • array concat / flatten
  • std.foldl / std.foldr
  • std.join
  • materialization and rendering

Design Shape

The abstraction should be closer to an indexed lazy view than to Scala LazyList:

  • length is O(1)
  • eval(i) returns an Eval without forcing where possible
  • value(i) forces and caches according to existing Jsonnet semantics
  • asLazyArray / materialization remains available for legacy consumers
  • fast bulk APIs can support consumers without each one hand-writing type branches

Possible API sketches:

def foreachEvalFast(f: Eval => Unit): Unit
def copyEvalTo(out: mutable.ArrayBuilder.ofRef[Eval]): Unit
def copyStrictTo(visitor: Visitor[?, ?]): Unit

Constraints

  • Preserve lazy evaluation, trace behavior, and error retry behavior.
  • Preserve tailstrict boundaries.
  • Avoid turning random access into prefix evaluation.
  • Keep small arrays on simple JVM-friendly representations when that wins.
  • Avoid deep view trees causing stack depth or branch overhead problems.
  • Make materialization behavior explicit and measurable.

Candidate Implementations

  • strict array wrapper
  • mapped array view
  • makeArray view
  • slice view
  • repeated view
  • concat/chunked/rope view
  • range/byte specialized views

Acceptance Criteria

  • A small design note or PR description documents cache/error/materialization semantics.
  • At least one producer/consumer pair stops allocating unnecessary intermediate thunk arrays.
  • Benchmarks include both partial-indexing and full-consumption workloads.
  • Tests cover laziness, error retry, trace behavior, reverse/slice/repeat composition, and materialization.
  • The first implementation is small enough to review independently; larger fusion/chunked work can follow in later PRs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions