Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

alien-signals-java

CI

Signals, computed values, and effects for Java. A port of alien-signals 3.2.1, checked against upstream's own conformance suite.

Values recompute on demand, only when something reads them, and only when an input changed. It runs on one thread and needs no scheduler and no dependencies.

import static io.github.hbtweb.aliensignals.Signals.*;

Signal<Integer> count = signal(1);
Computed<Integer> doubled = computed(prev -> count.get() * 2);

effect(() -> System.out.println("count is " + count.get()));   // prints 1

count.set(2);                                                  // prints 2
doubled.get();                                                 // 4

Install

Not on Maven Central. Use JitPack, which builds this repo on demand:

<repositories>
  <repository><id>jitpack.io</id><url>https://jitpack.io</url></repository>
</repositories>

<dependency>
  <groupId>com.github.hbtweb</groupId>
  <artifactId>alien-signals-java</artifactId>
  <version>main-SNAPSHOT</version>
</dependency>

Pin a tag or commit hash rather than main-SNAPSHOT for anything you care about. Or build locally with mvn install, which gives you io.github.hbtweb:alien-signals:3.2.1.

Requires Java 17+. No runtime dependencies.

API

signal(v) a value that changes over time. get() and set(v)
computed(prev -> ...) a derived value. get() reads it. Cached
effect(() -> ...) runs now, and again whenever what it read changes
effectWithCleanup(() -> ... return cleanup) cleanup runs before each re-run and on disposal
effectScope(() -> ...) groups effects so one stop() disposes them all
batch(() -> ...) coalesce writes into a single notification
untrack(() -> ...) read without subscribing

effect, effectWithCleanup, and effectScope return an Effect. Call stop() to dispose it. A computed's function receives its last value, which helps when writing accumulators.

Effect e = effect(() -> { ... });
e.stop();

batch(() -> { a.set(1); b.set(2); });   // watchers run once, not twice

Effect scope = effectScope(() -> {
    effect(() -> ...);                   // both effects belong to the scope
    effect(() -> ...);
});
scope.stop();                            // disposes both

Change detection

A write that doesn't change the value propagates nothing. "Changed" means Objects.equals by default. A collection or record can be equal without being the same object. Such a write registers no change, and stops there.

That differs from the JavaScript original, which compares objects by reference and would re-run. It's the behaviour a Java caller expects, and it's what lets a recomputed result that still equals the old one stop a cascade. To get upstream's exact propagation, choose it per signal:

Signal<List<Integer>> s = signal(List.of(1, 2, 3), Signals.UPSTREAM);
Computed<int[]> c = computed(prev -> compute(), Arrays::equals);

Signals.VALUE is the default. Signals.UPSTREAM compares numbers, strings, and booleans by value and everything else by reference, matching the original exactly.

Thread safety

Single-threaded, like the original. The graph, the active subscriber, and the flush queue all share static state. Calling from more than one thread is unsafe.

Verification

1226 tests. Every one of the 179 cases in reactive-framework-test-suite, the suite upstream runs itself. Then a differential fuzzer builds randomised graphs and runs them against this port and the real upstream JavaScript, comparing values and also how many times each node recomputed.

mvn test

VERIFICATION.md covers what those oracles catch and what they miss. bench/ holds Java Microbenchmark Harness (JMH) benchmarks. Read bench/PROVENANCE.md before trusting a number from them.

Versions

Tracks upstream npm. This is 3.2.1 because it ports alien-signals 3.2.1.

License

MIT. Original TypeScript © Johnson Chu. The Java port © hbtweb. See LICENSE.

About

Signals, computed values and effects for Java 17+. A port of stackblitz/alien-signals 3.2.1, verified against upstream's own conformance suite and by differential testing against the original JavaScript.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages