Skip to content

Conversation

@pearmini
Copy link
Collaborator

@pearmini pearmini commented Sep 20, 2025

Related Issue #50
Ref. Observable Mutable
Ref. Observable Framework Mutable
Ref. Observable Framework Converting Mutable
Ref. Observable Notebook Kit Source
Ref. Add Observable Plot Attribution to Mosaic

Given this code snippet:

let a = 0;

a += 1;

echo(a);

If we transpile to the following snippet, it won't work. Because outside the codeblock defining a mutable, it's just a normal value, without value property:

const a = __mutable__(0);

a.value += 1; // a.value is undefined 

echo(a); // 1

What if we expose a setter from the defining place? It still doesn't work as expected. The block setA(a+1) results in incrementing forever. Because it reference a and mutate a, and every block referencing a reruns when a is mutated.

const [a, setA] = (() => {
  const a = __mutable__(0);
  return [a, (value) => a.value = value];
})();

setA(a + 1);

echo(a);

How about we expose a setter as well? It works. Because setA(getA() + 1); doesn't reference a anymore!

const [a, setA, getA] = (() => {
  const a = __mutable__(0);
  return [a, (value) => a.value = value, () => a.value];
})();

setA(getA() + 1);

echo(a);

In order to make mutable more transpiling-friendly, changes API a little bit. Then converts a to mutator$$a.value.

const [a, mutator$$a] = __mutator__(0);

mutator$$a.value += 1;

echo(a);

But this brings another question: When should we transpile a to mutator$$a.value, and when should we leave it as is?

We can't transpile all of them to mutator$$[NAME].value, because they are not reactive anymore.

let a = 0;

setTimeout(() => {
  a += 1;
}, 1000);

echo(a); // !!!! 0 instead of 1

// ------------------>

const [a, mutator$$a] =  __mutator__(0);

setTimeout(() => {
  mutator$$a.value += 1;
}, 1000);

echo(mutator$$a); // mutator$$a is not a mutable 

My intuition is that if a codeblock mutates the mutatble, then transpile it, otherwise don't. But what if a block mutates and references a mutable:

let a = 0;

setTimeout(() => {
  a *= 10;
}, 1000);

{
  a += 1;
  echo(a); // !!! 1 instead of 11
}

This will not work as expected either. So I guess we should discourage this usage? Because you can always split them up:

let a = 0;

setTimeout(() => {
  a *= 10;
}, 1000);

a += 1;

{
  echo(a); // 10
}

@pearmini pearmini marked this pull request as draft September 20, 2025 03:27
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Sep 20, 2025

Deploying recho with  Cloudflare Pages  Cloudflare Pages

Latest commit: dcd1c0b
Status: ✅  Deploy successful!
Preview URL: https://fb16d009.recho.pages.dev
Branch Preview URL: https://mutable.recho.pages.dev

View logs

@pearmini pearmini changed the title Add mutable Add __mutator__ Sep 20, 2025
@pearmini pearmini requested a review from chengluyu September 20, 2025 14:19
@pearmini pearmini force-pushed the main branch 9 times, most recently from 3f305c5 to 9edb43c Compare October 6, 2025 13:46
@pearmini pearmini force-pushed the main branch 3 times, most recently from 5c9c667 to 5dbb7e0 Compare October 20, 2025 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants