Changing an array

I’d like to let some code in a cell change an array defined in another cell. I have made the following notebook to (hopefully) clarify what I want to achieve : https://observablehq.com/@mavromatika/changing-an-array

I get the feeling that I haven’t understood how Observable works.

It already achieves what you want, but because it does so by bypassing Observable’s reactivity the view into myArray is not updated. If you change the last cell into this you’ll see the updated array:

{
  myArray[value] = "That one !"
  return myArray
}

Note that the lack of reactivity also means that you have to manually update other cells that depend on the array (or at least, the ones that you want to be reactive to these changes)

Generally speaking you should try to avoid this unless it’s really necessary for performance reasons, because you’ll run into bugs with stale state very easily. Plus it’s a lot harder to reason about the code.

So a better approach here is likely to be combining both the cell where you declare the array and update it:

myArray = {
  let myArray = ["bread","butter","strawberry jam"]
  myArray[value] = "That one !"
  return myArray
}

That way, you keep all the reactivity that makes coding in Observable so pleasant.

Thank you for this very clear and useful answer.

You’re very welcome!

By the way, if you check out the notebook that I linked you can see one example of the kind of bugs mentioned: changing the slider replaces the other values in the array with "That one !" as well, without resetting the other overwritten values back.

Now, this may actually be what you want in some very specific instances, but in most cases it’s not, right?

Yep, and to elaborate on @Job’s answer, I’ll adapt a passage from a forthcoming tutorial:

A good rule of thumb is that a cell should either define a named value to be referenced by other cells (such as myArray in your notebook), or it should display something informative to the reader (such as a chart or a cell which inspects a value).

A critical implication of this rule is that you should avoid implicit dependencies between cells: only depend on what you can name.

Why? A notebook’s dataflow is built from its cell references. If a cell doesn’t have a name, it cannot be referenced and cells that implicitly depend on its effect may run before it. (Cells run in topological order, not top-to-bottom.) Implicit dependencies lead to nondeterministic behavior during development, and possible errors when the notebook is reloaded!

For example, if one cell defines an array and a second cell modifies it in-place, other cells may see the array before or after the mutation. To avoid this nondeterminism, make the dependency explicit by giving the second cell a name and copying the array using Array.from or array.map. Or combine the two cells so that only the already-modified array is visible to other cells.

2 Likes