svelte icon indicating copy to clipboard operation
svelte copied to clipboard

Svelte 5: Incorrect Compiler Output With Private Fields

Open abdel-17 opened this issue 1 year ago • 3 comments

Describe the bug

class Box {
	#value = $state();

	swap(other) {
		const value = this.#value;
		this.#value = other.value;
		other.#value = value;
	}
}

The compiler converts other.#value = value; to $.get(other.#value) = value;.

Reproduction

https://svelte.dev/playground/untitled?version=5.1.3#H4sIAAAAAAAAE22OQWrDMBBFrzJMu3DAOHsnKTRddZUDVF0oYkoMiiQ0366L8d2L6jqk0NUw778_zMTBXoVbfg0u5iwO9BKvqfOS6dQj9eCaPzovyu3bxPhKRS6A67X6nFKjg3gUdrYq_3EXAyRAueW9utwlPJlg4LxVpWMcaSqrwcNgfS90oEeFhVSbnQlLop82VREXyZtVNnAxKGjt4NJps1zYrcYdowP99Ju_xsJuyn04lzGbsN_-_sw1Q0Zwi9zL_D5_A7TBU9ZAAQAA

Logs

No response

System Info

Not necessary

Severity

annoyance

abdel-17 avatar Oct 27 '24 06:10 abdel-17

Not sure if my input is helpful, but I see two potential ways to fix this issue.

Solution 1: Don't mess with how getters and setters are called.

Although, this might slightly decrease performance, it avoids weird bugs like this from coming up in the future. You would have to store the itself state in a separate private variable.

class Box {
	#var0 = $.state();

	get #value() {
		return $.get(this.#var0);
	}

	set #value(value) {
		$.set(this.#var0, value);
	}

	swap(other) {
		const value = this.#value;
		this.#value = other.value;
		other.#value = value;
	}
}

Solution 2: Handle private field access for external variables differently.

An admittedly hacky way to solve this is to first check if the field a signal first. You can also skip this step for private fields that aren't declared as $state.

class Box {
	#value = $.state();

	swap(other) {
		const value = this.#value;
		this.#value = other.value;
		if ($.is_state(other.#value)) {
			$.set(other.#value, value);
		} else {
			other.#value = value;
		}
	}
}

abdel-17 avatar Oct 31 '24 03:10 abdel-17

I really don't want to be annoying, but is there any progress on this issue? I worked around it for now by manually defining setters Java-style.

class Box {
  #setValue(value) {
    this.#value = value;
  }
}

abdel-17 avatar Nov 17 '24 22:11 abdel-17

I really don't want to be annoying, but is there any progress on this issue? I worked around it for now by manually defining setters Java-style.

class Box {
  #setValue(value) {
    this.#value = value;
  }
}

Don't worry, I actually forgot about this issue so good that you pinged hete... I'll look into it tomorrow if I can

paoloricciuti avatar Nov 17 '24 23:11 paoloricciuti