Liking cljdoc? Tell your friends :D

Tests, builds and benchmarks

Development guide

Run commands from the repository root.

JDK requirement

The value-path tests need a JDK with JEP 401 value classes: the Valhalla early-access build selected by the JVM facts. Array tests also need its javac and the internal-package export shown below. Other JDKs do not have value classes. On another JDK, the environment test fails and names the cause.

Select the JDK

The clojure script uses JAVA_CMD first. Set it to the java of the Valhalla JDK. <valhalla-jdk-home> is the home directory of the Valhalla JDK.

export JAVA_CMD=<valhalla-jdk-home>/bin/java

JAVA_HOME alone is not sufficient: the clojure script uses java on PATH before JAVA_HOME.

Facts-based executable selection

The development-only JVM facts define role builds, archives and separate flag profiles. value-type.jvm-executable/resolve! accepts a selected facts entry, an environment map and a provisioning root. It checks the exact java.runtime.version of the executable, including overrides. It does not add preview or export flags during this check.

The default provisioning root is ~/.cache/value-type/jvms/. Executables are under <root>/<role>/<build>/<platform>/<archive-java-layout>. Explicit VALUE_TYPE_BASELINE_JAVA, VALUE_TYPE_VALHALLA_JAVA and VALUE_TYPE_SMOKE_JAVA paths take precedence for their respective roles. Blank overrides use the provisioned path. Missing executables and build mismatches fail rather than select another JVM. The supported host platforms are Linux x64, Linux ARM64 and macOS ARM64. Linux aarch64 and arm64 select native ARM64 archives for all three roles. The baseline archive on macOS uses x64 and requires Rosetta.

Linux ARM64 supports local release preview without x64 CPU emulation. Checked provisioning and the complete staged preview sequence pass on native ARM64; task 027 evidence records build identities, commands and results. Hosted CI stays on Linux x64. Local ARM64 results do not establish x64 or hosted execution success.

Install the selected builds with checked provisioning:

bb jvm:provision baseline
bb jvm:provision valhalla
bb jvm:provision ordinary

For a new installation, each command downloads the archive, checks its SHA-256 before extraction and verifies the exact build before installation. If the role/build/platform directory already exists, the command checks only the executable and its exact build identity. Repeat calls do not download the archive or hash the installed files; this build check does not verify archive integrity.

Each command prints the executable path. Optional arguments select PLATFORM and ROOT: bb jvm:provision ROLE [PLATFORM [ROOT]]. To request a fresh checked installation, select a new ROOT with no installation for that role, build and platform. Provisioning does not use executable overrides. Set JAVA_CMD separately for the parent CLI process; role overrides select the test consumers. Compatibility and build consumers use these verified roles and separate profiles, not the parent's flags.

Test layout

Tests share one parent directory, but use separate class path roots:

DirectoryPurpose
test/runtime/Library tests on Valhalla with preview enabled.
test/compatibility/Per-parent fallback, AOT and startup checks, and shared child-JVM test support.
test/cross-jvm/Cross-JVM policy, transfer, AOT, array and capability report matrices.
test/smoke/Ordinary-JDK startup, policy and same-JDK AOT checks.
test/jvm/Facts, executable selection, provisioning and runner configuration.
test/build/Build contracts and isolated JAR consumers.
test/release/Release tooling contracts.
test/tooling/API, lint, prose, Git-hook and CI checks.
test/resources/Java fixtures and the isolated consumer script.

Do not add the parent test/ directory to the class path or use it for test discovery. Select a suite with --dir, as shown below. Compatibility tests must not load the value-only runtime helpers or inherit preview flags. Resources are copied or compiled explicitly; they are not a class path root. The tooling test alias is :tooling-test; API generation uses :quickdoc.

Run the tests

clojure -J--add-exports=java.base/jdk.internal.value=ALL-UNNAMED -M:test -m scry.cli --dir test/runtime

The command exits 0 only when at least one test runs and all tests pass. Failure details go to .scry-results/. Each run replaces that directory; retain results before the next run. The :test alias enables preview, but does not add the export. Do not use it for preview-free controls.

Smoke and forced-JIT tiers

The primary baseline/Valhalla pair retains the full matrix. The ordinary role is smoke-tested, not full-matrix tested. Run the tooling and smoke suites:

clojure -M:jvm-test
clojure -M:smoke-test

The smoke children use the ordinary role normally, without preview or exports, with explicit value-type.value-classes=auto. They check warning-free loading, the java.lang.classfile API, the absent value predicate and :missing-value-predicate. Fresh silent/warn/error processes check two definitions, identity behavior, one warning under warn, and rejected definitions under error. A silent AOT producer and separate source-free consumer use the same JDK. There are no cross-JVM or interpreter rows for this role.

Run the value and array suites with forced compilation:

bb test:forced-jit

The runner selects and verifies this revision's Valhalla role. It adds preview, exports, explicit auto and -Xcomp -Xbatch -XX:-TieredCompilation to the Scry parent: compile on first invocation, wait for compilation, and use the optimizing compiler. It discovers only test/runtime/. Nonempty JAVA_TOOL_OPTIONS, JDK_JAVA_OPTIONS or _JAVA_OPTIONS are rejected.

Forced compilation covers the parent, including AOT production. The runtime AOT consumers and fresh-process probes remain normal preview-only children. A pass is not forced-JIT child evidence. The runner reports build, flags and duration; Scry exit status and failure-file rules apply.

To admit a new EA build, change the primary Valhalla facts entry as a candidate. Run this command on that exact candidate configuration, not the previous build. Record the command, build identity, flags, duration and result in the change's implementation evidence. Accept only after a pass; configuration changes need another pass. Failed candidates do not replace the accepted build. Full-matrix and release checks still apply. Change the JVM format row too if required.

Verified fallback matrix

Tests use Clojure 1.12.6 with the baseline and Valhalla roles in the JVM facts, with preview disabled and enabled. This is tested coverage, not a new minimum JDK or a claim about future EA formats. Run the separate fallback suite without inheriting the value-only alias:

JAVA_CMD=<java8-home>/bin/java clojure -M:fallback-test
JAVA_CMD=<valhalla-jdk-home>/bin/java clojure -M:fallback-test
JAVA_CMD=<valhalla-jdk-home>/bin/java clojure -J--enable-preview -M:fallback-test
JAVA_CMD=<java8-home>/bin/java clojure -M:cross-jvm-test

The cross-JVM tests need both executables. Set VALUE_TYPE_BASELINE_JAVA and VALUE_TYPE_VALHALLA_JAVA to their full executable paths when they are not in the provisioning directory described above. The focused :cross-jvm-test commands below use JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA"; set this variable before you run them. If it is not set, JAVA_CMD is empty and the parent uses java on PATH. Build tests use both JVMs for isolated JAR consumers. Fallback tests use real processes, including source-free AOT consumers, and the same Scry exit/failure rules.

The :cross-jvm-test alias runs test/cross-jvm/ once. Its owner parent is Java 8. Each child takes its executable, options and class path from the test configuration, not from the parent, so another parent adds no coverage. Do not run cross-JVM namespaces with :fallback-test; Scry reports a runner error.

Child JVMs

VALUE_TYPE_TEST_JVM_LIMIT sets how many child JVMs run at the same time. The value is a positive decimal integer, at most 2147483647 (Integer/MAX_VALUE); the default is 4. An invalid value fails the load of the test support with the variable name and value. Scry reports a runner error, runs no tests and exits 1.

A child times out after :timeout-ms (default 120000 ms) plus 10000 ms for each cell after the first. The time starts when the process starts; the wait for a free slot is not included.

A child can run more than one cell. Each cell has its own namespace, its own Compiler/LOADER binding and its own *out* and *err*. Each cell that defines a type checks that the Class is new in the JVM. Cells share a child only when they have the same values for these axes:

  1. Java executable and JVM options.
  2. Fallback policy.
  3. Producer or consumer role.
  4. AOT artifact (a source-free consumer loads exactly one artifact).
  5. First-event evidence: first capability detection, the first policy read, require order, warning scope across runtimes, or the first load of an AOT namespace. Such a cell has its own child.

In a warn child, only the first fallback cell writes the warning line. Each grouped warn fallback cell has a matching error fallback cell in the same test namespace (not always the same test). For example, the transfer-test constrained-warning cells match constrained-concurrent-strict-test. The error cell gives the guard evidence for the form and mode of the warn cell, and the repeated-rejection evidence.

After a change to the test support, run its in-process tests. They take seconds and start no child JVM:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.aot-fixture-test \
  --namespace value-type.cell-outcomes-test \
  --namespace value-type.cell-registry-test \
  --namespace value-type.jvm-runner-test \
  --namespace value-type.label-record-test \
  --namespace value-type.unavailable-predicates-test

Add --namespace value-type.cell-runner-test for the runner cases that start child JVMs: policy rules, cell isolation, failing, crashing, unreadable and timed-out children, a producer with an unreadable result, a child that does not start, the child limit with its permit-wait rule, and the read of VALUE_TYPE_TEST_JVM_LIMIT when value-type.jvm-runner loads.

Set VALUE_TYPE_TEST_RECORD to a file path to write a record of child starts, labels and times for each test Var. The record is off when the variable is not set.

Verify portable non-nil fields

Set VALUE_TYPE_BASELINE_JAVA and VALUE_TYPE_VALHALLA_JAVA to the Java 8 and facts-selected Valhalla executable paths. The following checks need no internal-package exports:

JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure -M:fallback-test \
  --namespace value-type.fields-test
JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.field-capability-test \
  --namespace value-type.field-transfer-test \
  --namespace value-type.field-aot-test \
  --namespace value-type.public-field-aot-test \
  --namespace value-type.public-native-field-aot-test \
  --namespace value-type.public-mixed-field-aot-test

The parent needs neither preview nor exports. Children select their flags explicitly. These checks cover native capability, declaration errors, repeated policy rejection, transferred expansions and source-free AOT consumers. The AOT suite deletes and excludes producer sources, compiles separate Clojure and Java consumers, and checks incompatible receivers. Java compilation uses the compiler in the facts-selected Valhalla JDK; a Java runtime alone is not sufficient.

Representation and enforcement are separate. On Java 8 and preview-disabled EA3, silent and warn permit identity output with generated constructor checks; error rejects identity fallback. On preview-enabled EA3, native-eligible fields use native enforcement. Other concrete class tags use generated checks without a fallback warning under all three policies. Both paths retain concrete final storage and reject nil and wrong-type constructor arguments.

The public transfer and AOT tests cover fixed identity-generated, value-generated, native and mixed modes. Incompatible receivers reject fixed value output rather than select identity output. Direct Java class access does not evaluate Clojure namespace policy guards; constructor checks still apply. These tests use real child JVMs. Changing parent flags does not add child configurations.

Run focused receiving checks in normal and interpreter execution:

for mode in normal interpreter; do
  flags=()
  if [ "$mode" = interpreter ]; then flags+=(-J-Xint); fi
  for java in "$VALUE_TYPE_BASELINE_JAVA" "$VALUE_TYPE_VALHALLA_JAVA"; do
    JAVA_CMD="$java" clojure "${flags[@]}" -M:fallback-test \
      --namespace value-type.identity-receiving-test || exit 1
  done
  JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure "${flags[@]}" \
    -M:test -m scry.cli \
    --namespace value-type.value-receiving-test || exit 1
done
JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.identity-receiving-cross-jvm-test

These local controls cover constructor checks, receiving analysis and Class identity after redefinition. They do not replace the separate policy, transfer or AOT tests.

Run the controlled-capability check separately:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.controlled-field-capability-test \
  --namespace value-type.function-redefinition-test

This check replaces only the native capability result in child JVMs. It is controlled-capability evidence, not a supported JVM configuration. Keep it separate from real-JVM capability results.

Accepted evidence limits: packaging checks cover the silent policy only, and the explicit child-JVM matrix is the evidence scope.

Run the native field semantic matrix in Bash:

export JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA"
for flatten in + -; do
  for mode in normal interpreter; do
    flags=()
    if [ "$mode" = interpreter ]; then flags+=(-J-Xint); fi
    clojure "-J-XX:${flatten}UseFieldFlattening" "${flags[@]}" \
      -M:test -m scry.cli \
      --namespace value-type.non-nil-fields-test \
      --namespace value-type.impl.loader-test \
      --namespace value-type.impl.transform-test \
      --namespace value-type.impl.field-access-test \
      --namespace value-type.impl.field-storage-test || exit 1
    test -z "$(find .scry-results -type f -print)" || exit 1
  done
done

The alias supplies preview, not exports. Keep this control separate from the full runtime suite, which needs exports for arrays. All four runs must pass; stop on failure before another run replaces the failure files. These checks verify construction, reads, mixed primitive slots, methods and companions. They do not assert flat storage or establish performance. The tested builds are those in the fallback matrix above, not future JVM formats.

Verify deftype* forms

Set VALUE_TYPE_BASELINE_JAVA and VALUE_TYPE_VALHALLA_JAVA to the Java 8 and facts-selected Valhalla executable paths. These checks need no internal-package exports. Run the value-path checks on facts-selected Valhalla with preview:

JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure -M:test -m scry.cli \
  --namespace value-type.deftype-star-test \
  --namespace value-type.deftype-star-record-test \
  --namespace value-type.impl.removed-field-test \
  --namespace value-type.value-receiving-test \
  --namespace value-type.impl.transform-test

These checks cover declaration errors and their order, plain, record and closed shapes in both outputs, non-nil fields (all shapes, both outputs), the record transform, the record storage bytecode, the removed-field access check and the receiving order and errors of value-field-deftype*. For the closed shape, they also cover :value-type/closed option errors and their order, construction and rejection in both outputs, the closed bytes and removed-field access for __meta, __extmap, __hash and __hasheq.

Run the policy and transfer checks on the three JVMs:

for c in "$VALUE_TYPE_BASELINE_JAVA|" "$VALUE_TYPE_VALHALLA_JAVA|" \
         "$VALUE_TYPE_VALHALLA_JAVA|-J--enable-preview"; do
  JAVA_CMD="${c%|*}" clojure ${c#*|} -M:fallback-test \
    --namespace value-type.runtime-test \
    --namespace value-type.deftype-star-transfer-test \
    --namespace value-type.identity-receiving-test \
    --namespace value-type.identity-backend-test || exit 1
done
JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.deftype-star-aot-test

value-type.deftype-star-transfer-test is in test/compatibility/, so it runs with :fallback-test. These checks cover the fallback policies with non-nil fields, the transfer of enabled fields, the receiving order and errors of identity-field-deftype*, the D8 delegation rule of the identity backend, the closed transfer cells and the closed identity backend cases. The AOT test fixes the representation and enforcement at compile time and checks source-free consumers and incompatible receivers. Its fixtures include PlainNonNil, RecNonNil, Closed and ClosedNonNil.

Limits: interpreter (-Xint) runs cover only the value artifact consumers of the AOT test. Reflective access to __hash and __hasheq, and to __meta and __extmap of closed value output, is not checked. The feasibility gate for record-shaped value classes, the non-nil gate (dev/spike/record-value-type/non-nil-gate.clj) and the closed gate (dev/spike/record-value-type/closed-gate.clj) have their own commands in dev/spike/record-value-type/README.md. The non-nil gate and the closed gate need --add-exports=java.base/jdk.internal.value=ALL-UNNAMED. The EA3 flat-array evidence for closed records (closed-record-layout-test in value-type.array-info-test) runs with the runtime array checks in "Verify array diagnostics", which add this export.

Verify array allocation

Set both cross-JVM executable paths explicitly:

export VALUE_TYPE_BASELINE_JAVA=<java8-home>/bin/java
export VALUE_TYPE_VALHALLA_JAVA=<valhalla-jdk-home>/bin/java
JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test --namespace value-type.array-matrix-test

This test checks six configurations: Java 8; EA3 without preview, with and without exports; EA3 with preview but no exports; EA3 with preview and exports; and the supported configuration with array flattening disabled. Each configuration tests all three class-fallback policies and both require orders of value-type.core and value-type.array. Child flags are explicit; the parent does not need preview or exports. Unsupported configurations check safe loading and repeated capability errors, not value allocation. Child JVMs run the cells under the rules in "Child JVMs". The full :cross-jvm-test command above also includes this matrix.

Run native semantics and layout checks with flattening disabled:

JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure \
  -J--add-exports=java.base/jdk.internal.value=ALL-UNNAMED \
  -J-XX:-UseArrayFlattening -M:test -m scry.cli --dir test/runtime \
  --namespace value-type.array-test --namespace value-type.array-layout-test

Repeat with -J-XX:+UseArrayFlattening for the enabled control. A non-flat restricted atomic array is valid. These checks use real JVM allocation and stores; they do not establish support for other JDK builds. See the allocation guide for the public contract.

Verify sequence construction

Use the explicit executable paths from "Verify array allocation":

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.array-sequence-boundary-test

This matrix uses the same six configurations, three fallback policies and both require orders as allocation. Each child has the timeout in "Child JVMs" and must exit zero with complete EDN results and no fallback warning. Unsupported configurations reject both forms repeatedly before input effects. Supported configurations check component type, length and ordered contents for both forms, plus explicit-seed nil input. Export-only EA3 does not enable sequence construction. Child flags are explicit; the parent needs neither preview nor exports. The full :cross-jvm-test suite includes this matrix.

Run construction, allocation and layout checks together:

JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure \
  -J--add-exports=java.base/jdk.internal.value=ALL-UNNAMED \
  -J-XX:+UseArrayFlattening -M:test -m scry.cli --dir test/runtime \
  --namespace value-type.array-sequence-test \
  --namespace value-type.array-test --namespace value-type.array-layout-test

Repeat with -J-XX:-UseArrayFlattening. Sequence checks use real arrays and stores without diagnostics or a flat-layout requirement. They cover finite input, seed and indexed-element errors, one input traversal, input exceptions and later slot stores. The length boundary check uses internal arithmetic, not a large allocation. These checks do not establish streaming behavior or performance. See the sequence guide for temporary storage and failure-side-effect limits.

Verify array diagnostics

Use the explicit executable paths from "Verify array allocation". Run the public validation and inspection checks in disposable JVMs first:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.array-info-boundary-test

This namespace checks all six startup configurations, all three fallback policies and both require orders. Each child has the timeout in "Child JVMs" and must exit zero with complete EDN results. Independent native observations separate API absence from denied invocation access. Invalid public inputs (null, non-arrays and primitive arrays) must report :invalid-array before inspection capability is checked. A valid Object array reports :array-inspection-unavailable on Java 8 or EA3 without the export.

EA3 with the export can inspect ordinary reference arrays without preview. This does not enable value-class creation or allocation. The export-only checks verify that inspection works before and after allocation fails. The parent command adds neither preview nor exports; child flags are explicit. Do not add global flags to make unsupported controls pass.

Never call native diagnostics with null. All three native array queries crashed the tested EA3 JVM on null. Keep invalid public-input checks in children, not a shared REPL. Do not rerun task 012 crash probes as library tests.

After the disposable checks pass, compare valid-array results with direct JDK queries and run allocation/layout regressions:

JAVA_CMD="$VALUE_TYPE_VALHALLA_JAVA" clojure \
  -J--add-exports=java.base/jdk.internal.value=ALL-UNNAMED \
  -J-XX:+UseArrayFlattening -M:test -m scry.cli --dir test/runtime \
  --namespace value-type.array-info-test \
  --namespace value-type.array-test --namespace value-type.array-layout-test

Repeat with -J-XX:-UseArrayFlattening. Disabled flattening must not remove null restriction or atomic access. These tests compare all five properties, including empty arrays and a wider non-flat fixture, and check unchanged contents before and after caller stores. Atomic access does not guarantee compound updates, safe publication or caller synchronization. See the inspection guide for the public contract.

Verify the capability report

Use the explicit executable paths from "Verify array allocation". Run the report matrix in disposable JVMs:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.capability-matrix-test

This namespace checks all six startup configurations, all three fallback policies and three require orders (rotations of value-type.capability, value-type.core and value-type.array): 54 children. Each report must equal the expected row plus :fallback-policy of the cell policy, agree with definition, :non-nil field and array outcomes, and stay equal on a second call.

Run the controlled value-class check separately:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.controlled-value-capability-test

It replaces value-type.impl.capability/capability in an EA3 export child. It checks that the report (:value-class, :native-non-nil-field and :array-allocation), make-array and the definition read the replaced result, and that :array-inspection stays available. The "Verified fallback matrix" commands include the invalid-policy report check. See the capability report guide for the public contract.

Verify the fallback policy

Use the explicit executable paths from "Verify array allocation". Run the first-read checks in disposable JVMs:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.fallback-policy-test

This namespace runs 11 children:

  • A policy set after load applies: Java 8 and preview off, error and warn (4).
  • A property change after a report call has no effect: Java 8 and preview off (2).
  • An invalid launch policy throws at the first read: report on Java 8, preview off and preview on (3), or a definition on Java 8 and preview off (2). Each later read throws the same exception.

See the fallback policy guide for the public contract.

Verify the value-class switch

Use the explicit executable paths from "Verify array allocation". Run the switch checks in disposable JVMs:

JAVA_CMD="$VALUE_TYPE_BASELINE_JAVA" clojure -M:cross-jvm-test \
  --namespace value-type.value-class-switch-test

This namespace runs these children:

  • Report children on :export-off, :java8-off and :export-auto, each fallback policy (9). Under off the rows are :disabled and the definition falls back by policy with the :disabled detail. Under auto the rows equal the export rows.
  • Allocation messages: make-array and into-array on :export-off and :java8-off (2).
  • Invalid values OFF, off and the empty string on EA3 without the export and on Java 8 (6). Each entry point except array-info throws the same exception.
  • The policy-first child: an invalid policy and an invalid switch value on Java 8 (1). report throws the policy exception.
  • Probe loads: no probe class loads on :export-off, and a probe class loads on :export-auto (2).
  • The fixed read: a property change after a report call has no effect on :export-off (1).
  • AOT children: saved value output from an EA3 producer, run source-free on Valhalla:
    • Under off, output with native fields and output without native fields throw :value-capability-unavailable with reason :disabled at namespace initialization under each policy (3 per output).
    • Native-field output under OFF throws the invalid-value exception (1).
    • Saved function output loads under off, but each invocation throws :value-capability-unavailable with reason :disabled under each policy (3).
    • A controlled failed self-check rejects both saved outputs, with and without native fields, at namespace initialization under each policy (3 per output). The error is :value-capability-unavailable with reason :failed-self-check.

See the value-class switch guide for the public contract.

Build a local JAR

Run these commands from the repository root with the Clojure CLI and Git installed. Dependency downloads need repository access unless they are cached.

clojure -T:build jar
clojure -T:build clean

Both commands remove all existing target/ output, including target/object-size/ benchmark results. Copy any results you need to keep outside target/ first. jar cleans before packaging; clean only removes generated output and also succeeds when target/ is absent.

The artifact is target/value-type-0.1.N.jar, with Maven coordinates org.hugoduncan/value-type. N is git rev-list --count HEAD. The build/jar function returns the version and artifact paths:

{:jar-file "target/value-type-0.1.N.jar"
 :pom-file "target/classes/META-INF/maven/org.hugoduncan/value-type/pom.xml"
 :version "0.1.N"}

The JAR command needs Git and usable checkout history; failed Git commands or invalid counts cause an error, with no fallback version. The clean command does not need Git metadata.

A shallow checkout counts only available history. Different branches can have the same count, so this version is not a unique release ID. This command creates a local artifact; it does not install or publish it. See the release procedure for deployment, credential requirements and manual publication. The project has no published release.

The source-only JAR contains the library sources, Maven dependency and project metadata, and the full EPL-2.0 license. It contains no compiled classes, bundled dependencies, tests, benchmarks or build code. Packaging does not load or AOT-compile the library. Consumers still need the declared runtime dependencies. Value classes also need a supported JEP 401 Valhalla JDK with --enable-preview; other supported Clojure JVMs use the fallback policy for both ordinary definitions and enabled :non-nil fields. Permitted identity output retains concrete storage and generated constructor checks. Missing native field support alone does not require identity fallback or cause strict policy rejection. Fields need no internal-package export. The removed :nil-restricted key is rejected. See the portable field contract. Array allocation also needs --add-exports=java.base/jdk.internal.value=ALL-UNNAMED; it has no fallback.

Run the build tests

Select the supported Valhalla JDK with JAVA_CMD as above. These checks also need Git, the Clojure CLI and access to uncached dependencies.

clojure -M:build-test -m scry.cli --dir test/build

This separate suite checks the build contract in temporary projects and runs an isolated consumer with only the built JAR and runtime dependency JARs. The supported consumer gets preview and the internal-value export. Java 8 and preview-disabled EA3 consumers check safe loading and unavailable allocation without those flags. They also check that invalid diagnostic inputs keep their public error and valid arrays report inspection unavailable. An additional export-only EA3 consumer inspects an Object array before value creation while allocation remains unavailable. The supported consumer checks ordinary and restricted array diagnostics. It also checks both sequence forms, ordered contents and explicit-seed empty input. Unsupported consumers, including export-only EA3, reject both sequence forms repeatedly before value creation and without input effects. All consumers load library resources from the JAR, with no checkout sources on the class path. Each consumer also loads value-type.capability from the JAR, and its report equals the expected row for its configuration (:java8, :no-options, :export-only or :export). Nested Point/String non-nil fields also retain concrete storage and direct/factory constructor checks on Java 8 and EA3 preview off/on under silent. These packaging checks do not establish all-policy field coverage. Consumers select the baseline and Valhalla facts roles; use VALUE_TYPE_BASELINE_JAVA and VALUE_TYPE_VALHALLA_JAVA to override their paths. It selects test/build/; it does not replace the library test command above. Exit status and failure files follow the same Scry rules.

Run the benchmark

The method-call benchmark compares defvaluetype with deftype. Set JAVA_CMD to the Valhalla java (see "Select the JDK"), then:

clojure -M:bench -m value-type.bench

An optional argument sets the array length (default 1024). It must be an integer from 1 to 2147483647, inclusive (the JVM array-length range). Available memory can impose a lower limit. Invalid input is rejected before measurement. The results are in ramora/defvaluetype-design/benchmark.md.

Compare array storage and traversal

The typed-array benchmark compares standard identity and value arrays with arrays from value-type.array/make-array. It measures retained storage, allocated bytes and sequential traversal time. It does not measure construction time.

bash dev/bench/typed-array/run.sh

The runner selects the Valhalla JDK and required JVM flags. See its instructions for JDK overrides, run length, output paths and result validation.

Compare standalone object size

Use a Valhalla JDK with JEP 401 support (see "Select the JDK"). Run from the repository root:

JAVA_CMD=<valhalla-jdk-home>/bin/java bash dev/bench/object-size.sh

This compares shallow size for paired types with 0–3 primitive long fields. The isolated :object-size alias enables preview and uses Criterium 0.5.251-ALPHA. The wrapper extracts its bundled native agent and loads it at JVM startup. This route is verified on macOS/aarch64.

Results and raw evidence go to target/object-size/results.edn and raw.edn; setup and measurement logs go to stdout.log and stderr.log in that directory. Each run replaces these four files. On a nonzero exit, inspect the logs. See the size report for the recorded results, environment and limits. This is a manual measurement, not a performance gate.

Start a REPL

clojure -J--add-exports=java.base/jdk.internal.value=ALL-UNNAMED -M:test:nrepl

The REPL has preview, the internal-value export and the test path. Run the tests in the REPL with:

(do (require 'scry.core)
    (scry.core/run {:namespaces ['value-type.environment-test]}))

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close