Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Turn Signal into @FunctionalInterface for simple computed signals #22121

@Legioth

Description

@Legioth

Describe your motivation

Given a component configured with a simple string concatenation, e.g. new Span("Name: " + name);, you might want to change the name into a signal so that the span text is automatically updated when the name changes.

The straightforward way of doing this would be to wrap the concatenation into a computed signal: new Span(Signal.computed(() -> "Name: " + nameSignal.value()));. This is relatively much boilerplate code for a conversion that is expected to be commonly used.

Another alternative would be to add a helper constructor to the component so that you can bind based on a format string, e.g. new Span("Name: %s", nameSignal);. While this is very compact, it requires changing the structure of the original implementation from "Name: +" to "Name: %s" and it also means that additional overloads would be needed in each component class.

Describe the solution you'd like

Change Signal into an interface annotated with @FunctionalInterface with T value() as the only method in the interface. Keep the existing instance logic in an AbstractSignal class implementing this interface as the base class for the regular implementations such as ValueSignal.

This makes it possible to signalify the original example by adding () -> to the beginning of the expression and changing name to nameSignal.value() so that the final implementation is new Span(() -> "Name: " + nameSignal.value());.

The static helper methods, e.g. effect, computed and runInTransaction should be moved to the interface so that Signal remains the main entry point for operating on signals. Some instance methods in Signal could technically be added as default methods in the interface, e.g. peek and map. I don't think we should include those methods since want to encourage using "proper" signals in cases where those methods would be useful.

A "simple" computed signal created in this way doesn't completely replace the "proper" Signal.computed construct since the proper signal also caches the value to avoid running the callback each time value() is invoked as long as no dependency has changed. We cannot make the @FunctionalInterface variant work in this way since an interface cannot define the instance fields needed for the cached value and dependency tracking.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    Done / Pending Release

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions