# Dependency-tracking reactivity

**URL:** <https://es.discourse.group/t/dependency-tracking-reactivity/966>\
**Category:** 💡 Ideas\
**Created:** [September 5, 2021, 4:56pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966 "2021-09-05T16:56:09Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [September 5, 2021, 4:56pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/1 "2021-09-05T16:56:09Z")

</div>

What if the language had dependency-tracking reactivity?

For example, with some contrived syntax, in the following example, any time foo or bar change, both values are logged to console:

```javascript
reactive foo = 0
reactive bar = 0

autorun {
  console.log(foo, bar)
}

setInterval(() => foo++, 1000)
setInterval(() => bar++, 820)

```

The `autorun` expression reruns any time any of the reactive variables (auto-detected dependencies of the autorun) change. By using the variables inside the autorun, the system automatically tracks those variables as dependencies of the autorun, and that's how it knows to automatically rerun the expression if any of the dependencies change.

For those not familiar with dependency-tracking reactivity, it is a key feature in these libs or frameworks (note that API naming varies across them):

- [Solid.js](https://www.solidjs.com/)
- [Qt QML](https://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html) (not for web)
- [Knockout.js](https://knockoutjs.com/documentation/computedObservables.html)
- [MobX](https://mobx.js.org/reactions.html) (popular with Facebook React)
- [Vue](https://v3.vuejs.org/guide/reactivity-fundamentals.html#declaring-reactive-state)
- [Svelte](https://svelte.dev/)
- [Meteor.js](https://docs.meteor.com/api/tracker.html)

and many more.

If we want to stop logging in the above example, we could perhaps write

```javascript
reactive foo = 0
reactive bar = 0

const stop = autorun {
  console.log(foo, bar)
}

setInterval(() => foo++, 1000)
setInterval(() => bar++, 820)

// Stop the autorun (stop logging) later:
setTimeout(stop, 10_000)

```

I also wrote about how dependency-tracking reactivity makes code shorter, cleaner, and more concise compared to other event patterns here:

> **[GitHub - lume/variable: Create reactive variables and observe their changes in...](https://github.com/lume/variable)**
>
> Create reactive variables and observe their changes in a simple and concise way with less code and less coupling. - GitHub - lume/variable: Create reactive variables and observe their changes in a ...

Do you think we can have a language-level dependency-tracking reactivity feature built in?

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [September 5, 2021, 5:28pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/2 "2021-09-05T17:28:39Z")

</div>

some related threads:

> [@Destiny Operator](https://es.discourse.group/t/destiny-operator/895):
>
> Take an example... let a = 0; let b = a + 1; a = 2; b = a + 1; Here throughout the program b is supposed to be the successor of a. Each time we reassign a, we need to explicitly mention b = a + 1. Can we have a destiny operator as mentioned in [this](https://paulstovell.com/reactive-programming/) article that will bind a variable to its dependencies? let age = 13; const isEligible \<= age \> 18; // -\> False In the above above code, isElgible is bound to age \> 18. Instead of storing a boolean, it keeps an expression in memory. Whenever we m…

> [@JS Proposal: Auto Wire](https://es.discourse.group/t/js-proposal-auto-wire/900):
>
> Reactivity API to wire any reactive libs and native states together. It allows to mix different reactive libs, use async functions with automatic dependency tracking, observe any states in same way, make native DOM reactive etc.

> [@Reactive Variables / Native Binding](https://es.discourse.group/t/reactive-variables-native-binding/306):
>
> Data binding has gotten to be very popular and widely considered essential in JavaScript projects today. Many of our current frameworks today sprang up in one form or another to tackle this hurdle specifically. The concept of "These variable should always refer to the same thing" has been expressed in many ways through various languages: pointers, refs, aliases. Some even more ambitious ideas have been explored such as the destiny operator. In many of these cases, the programmer consuming the b…

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [September 5, 2021, 11:40pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/3 "2021-09-05T23:40:28Z")

</div>

[Actors](https://es.discourse.group/t/actors/801) Beat you to it, just in a slightly different flavor. 😉

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [September 24, 2021, 1:50am UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/4 "2021-09-24T01:50:48Z")

</div>

I think Actors is on a better path than most frameworks using today's JS syntax except for the ones with dependency-tracking reactivity and fine-grained updates. I replied there on how I think syntax could be, and to me it feels more natural that way.

Are you familiar with [Qt](http://qt.io/)? Dependency-tracking reactivity is built into Qt's QML+JavaScript language.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [April 13, 2022, 12:18am UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/5 "2022-04-13T00:18:36Z")

</div>

Many of us in the Solid.js community have been thinking about this. I think that for this to work, it needs unique syntax so that it is essentially new primitives that don't conflate with existing paradigms in the language, like I described in a comment to [Ryan's article](https://dev.to/ryansolid/comment/1me77):

> **[Discussion of The Quest for ReactiveScript](https://dev.to/trusktr/comment/1k2mi)**
>
> This article isn't going to teach you about the latest trends in frontend development. Or look in...

With syntax being bike sheddable, that comment, plus this snippet gets the idea across:

```nohighlight
export signal count@ = 0

// increment it every second
setInterval(() => count@++, 1000)

```

```nohighlight
import {count@} from './count.js'
import {someOtherValue@} from './somewhere.js'

const effect = effect {
  // This runs any time either count@ or someOtherValue@ change, batch-deferred in the next microtask after either was modified
  console.log('values are: ', count@, someOtherValue@) 
}

// any time later,
effect.stop()

```

Sometimes we want read-only signals:

```nohighlight
signal _count@ = 0

@readonly // perhaps using a future decorators proposal, decorating the export
export signal count@ = _count@

// increment it every second
setInterval(() => _count@++, 1000)

```

Or maybe we hav enew syntax for readonly derived values:

```nohighlight
signal _count@ = 0

export memo count@ {
  return _count@
}

```

or

```nohighlight
signal _count@ = 0

export memo count@ = _count@

```

Just food for thought, but the main idea is syntax differentiates the semantics from current JS features. The meaning of existing languages features is not ambiguous this way. A regular `var foo` will always operate like it currently does, never being a reactive signal (unless future declaration decorators are added, which allow people to achieve it via decorating get/set of a variable).

There would be a new "pass by signal" that passes the signal along, so that it can be reacted to anywhere. F.e.:

```nohighlight
signal foo@ = 123

setInterval(() => foo@++, 1000)

function makeAnEffect(bar@) {
  effect {
    console.log(@bar)
  }
}

var someVar = 456

makeAnEffect(123) // syntax error, 123 is not a signal, it cannot be passed to a signal parameter.
makeAnEffect(someVar) // syntax error, someVar is not a signal, it cannot be passed to a signal parameter.

makeAnEffect(foo@) // this works, foo@ is a signal, and the internal bar@ reads from it (merely an alternate name for the same signal within the function.

```

Without the syntax disambiguation, things will get very messy very quickly.

---

<div class="post-metadata">

**Author:** ![pygy](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/pygy/32/231_2.png) [@pygy](https://es.discourse.group/u/pygy)\
**Post date:** [April 16, 2022, 1:23pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/6 "2022-04-16T13:23:31Z")

</div>

You'd probably want a cleanup mechanism to go along with this (thinking of Surplus' S.cleanup or Solid's onCleanup hook).

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [February 28, 2023, 4:37am UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/7 "2023-02-28T04:37:15Z")

</div>

Yes indeed, I think we need the ability to cleanup when desired like in [S.js](https://github.com/adamhaile/S) or [Solid.js](https://solidjs.com/), but also it should implicitly cleanup (be garbage collected) if all dependencies are no longer referenced (also as with those libraries).

As for explicit cleanup, how could that look like?

```js
const effect = effect {
  // re-run when a, b, or c change
  console.log(@a, @b, @c)
}

// later:
effect.stop()

```

Maybe `effect` here is some sort of instance based on an `Effect` class that represents the effect. Similar to how a `Function` class represents instances of `function() {}` or `Array` represents `[]`.

Also effects should be synchronously dependent (children) of the effect they're created in, and would therefore also be cleaned up with their parent:

```js
const effect = effect {
  // re-run when a, b, or c change
  console.log(@a, @b, @c)

  const d@ = 0

  const interval = setInterval(() => @d++, 1000) // increment every second

  // inner effect (no need to keep a reference in this example)
  effect {
    // additionally log any time d changes
    console.log(@d)
  }

  // a "cleanup" block re-run any time the effect it is defined in re-runs (cleanup in S.js, onCleanup in Solid.js)
  cleanup {
    clearInterval(interval)
  }
}

// later:
effect.stop() // also cleans up the inner effect (and whichever interval is currently running)

```

This is very similar to [S.js](https://github.com/adamhaile/S) and [Solid.js](https://solidjs.com/), just in a syntactical form.

I think having this be a native feature would be great because:

- it is powerful for data modeling
- issues with debugging are eliminated: the JS engine can provide accurate call stack when an error is thrown, even on infinite recursion (it could throw if recursion is too big just like with functions), whereas with libs like S.js and Solid.js they have to catch errors and re-throw which can get problematic (the trace you see may not match with your actual source).
- With an official syntax, we can provide IDE tooling to help with best practices, f.e. we can syntactically highlight effects that are children or not children in differing ways, etc.
- Declarative toolchains (f.e. JSX compilers) can have a standard output for reactivity
- signals and effects can be implemented and optimized natively in the JS engine in different ways, while providing the top-level syntactical pattern
- ...

---

<div class="post-metadata">

**Author:** ![devshogun](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/devshogun/32/1666_2.png) [@devshogun](https://es.discourse.group/u/devshogun)\
**Post date:** [March 5, 2023, 10:54pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/8 "2023-03-05T22:54:31Z")

</div>

This is a great idea. Keywords and decorators are highly under utilized nowadays. This could change that and bring a new paradigm into the ecosystem

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/trusktr/32/183_2.png) [@trusktr](https://es.discourse.group/u/trusktr)\
**Post date:** [December 4, 2023, 10:22pm UTC](https://es.discourse.group/t/dependency-tracking-reactivity/966/9 "2023-12-04T22:22:33Z")

</div>

Some people have been saying that perhaps it makes sense to create a runtime API first, then syntax sugar after. For example, maybe we could start with built-in APIs like:

```js
const count = new Signal(0)

setInterval(() => count.value++, 1000)
// or setInterval(() => count.set(val => ++val), 1000)

const effect = new Effect(() => {
  console.log(count.value) // runs any time count changes
})

// later
effect.stop()

```

where `count.set(val => ++val)` is form that you'd use inside of an effect to avoid both reading and writing (infinite loop):

```js
const effect = new Effect(() => {
  count.value = count.value + other.value // this reads and writes count, causing a reactivity loop
})

```

vs

```js
const effect = new Effect(() => {
  count.set(val => val + other.value) // this only writes count, no reactivity loop (updates only on other.value changes)
})

```

With syntax sugar, the reactivity loop problem goes away:

```js
const effect = effect {
  count@ = count@ + other@ // this could be equivalent to using count.set() (read is always untracked in an expression that writes to the same variable)
}

```

```js
const effect = effect {
  count@ = count.value + other@ // escape hatch (count.value is tracked)
}

```

Would it make sense to have `untrack` API (and later sugar)?

```js
const effect = new Effect(() => {
  count.value = a.value + untrack(() => b.value) // update only if `a` changes
})

```

```js
const effect = effect {
  count@ = a@ + untrack { b@ } // update only if a changes (do{} syntax and similar semantics)
}

```

and shortcut for single untracked value:

```js
const effect = effect {
  count@ = a@ + b.raw // update only if a changes
}

```
