Skip to content

Ordering of reactive declarations isn't logical #4626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
antony opened this issue Apr 2, 2020 · 6 comments
Closed

Ordering of reactive declarations isn't logical #4626

antony opened this issue Apr 2, 2020 · 6 comments
Labels
awaiting submitter needs a reproduction, or clarification

Comments

@antony
Copy link
Member

antony commented Apr 2, 2020

Describe the bug
It looks like reactive properties don't follow the expected rules of declaration order. If I define a reactive property above a non-reactive property, the non-reactive property can't use it (Cannot access x before intiialization)

To Reproduce
https://svelte.dev/repl/fe808f17c1cb44909142e8ffd79260c6?version=3.20.1

Expected behavior
I'd expect that:

let x = y
$: x = y

would be the same in terms of declaration order.

Information about your Svelte project:

  • Svelte 3.20.1

Severity
Not huge, you can work around it, but it's a trip up for newbies:

let x
$: {
x = y
}
@Conduitry
Copy link
Member

It might make sense here to move the automatically created declarations up higher, but I'm worried that would also make things confusing. What is important here, and what I think shouldn't change, is that the reactive blocks are all separated out and potentially reordered, and run asynchronously, separate from other synchronous top-level code in the component. It's likely a mistake to be accessing reactively assigned variables synchronously during component initialization, but it would probably be impossible to catch all cases of that.

<script>
	let foo;
	$: foo = 42;
	console.log(foo);
</script>

This currently logs undefined, and I don't think that should change. Would it be confusing if

<script>
	$: foo = 42;
	console.log(foo);
</script>

produced valid code and did the same thing?

@Conduitry Conduitry added the awaiting submitter needs a reproduction, or clarification label Apr 2, 2020
@rixo
Copy link
Contributor

rixo commented Apr 3, 2020

I agree with @antony that the current behaviour does not match "natural" expectations and, as such, is a source of confusion. I personally consider this a bug.

For me at least, the natural expectation is that reactive declarations would be initialized synchronously in the order they appear:

<script>
  $: foo = 42
  console.log(42) // => 42
</script>

I personally think this is the only behaviour that doesn't need any further explanation. Otherwise you need to enter synchronous vs asynchronous considerations, etc. This is far less newbie friendly than just: "it reads top to bottom, and the magic is that the value stays in sync (i.e. the expression gets executed each time one of the variables in it change)".

Also, I know this is a weak argument, but this is what you would get in normal JS, if the $: label wasn't overloaded by Svelte.

Now I must concede that, concretely, I don't remember ever helping someone with this precise problem or a problem stemming from a confusion around this. So maybe it's just OP and me? That'd surprise me though...

In any event, with the current behaviour, for people with misaligned expectations like us, it would be catastrophically worse to mute the error by accepting this:

<script>
	$: foo = 42;
	console.log(foo); // => undefined
</script>

It would turn an easily identifiable in-your-face crash into a mystical bug hunt. I still get my fair share of such "Cannot access x before initialization" and, without the error, I could have a very hard time figuring the cause is this. On the other hand, the error message we're currently getting does give a pretty decent hint as to what is happening.

@antony
Copy link
Member Author

antony commented Apr 3, 2020

Points taken - thanks both! So there might be some options:

Option A: Emitting a warning in this instance, to say (Reactive declarations cannot be used during component initialisation) or something, but of course Reactive declarations can be used by other reactive declarations, so that's confusing too. (Also, @Conduitry alluded to the fact that this might not even be possible to catch)

Option B: Enforce reactive variables as the last item (other than methods) within a Svelte component. This is definitely a breaking change (unless turned into a warning), and I don't know if it might affect something else.

Option C: Do nothing. Perhaps add a little bit of documentation about it.

I'm happy to add the docs if it's option C. Thoughts?

@arxpoetica
Copy link
Member

Forcing option B definitely goes against the grain of natural JavaScript flow. My preference: A if possible, but if that's too tall an order or impossible, let's just document this idiosyncrasy until and/or when a better solution pops up.

@pushkine
Copy link
Contributor

pushkine commented Apr 4, 2020

duplicate #4516

this requires serious rethinking of how components are initiated in svelte

in the meantime an efficient way of sidestepping this issue could be to have the svelte formatter reorder expressions in the order they are run

@antony
Copy link
Member Author

antony commented Apr 4, 2020

Apologies this is indeed a duplicate. Closing in favour of #4516

@antony antony closed this as completed Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification
Projects
None yet
Development

No branches or pull requests

5 participants