(Links: https://github.com/remixlabs/protoquery/wiki/links)
This is an attempt to write up my understanding of the motivation for links and aliases, and where they can be used. It may be useful to others…
In mix there are two quite different objects you can work with: data and cells. Cells can hold data, but more importantly, cells express a spreadsheet dependence. A cell’s value can be a function of other cells, and when its dependencies change, it changes.
Expressions involving cells are special, because they are inherently cell-valued:
[1] > cell x = 1
x : data
[1] > cell y = x + 1
y : data
[1] > def z = x + 1
.:1:9 (to 1:10): Type error: cell inaccessible here: x
[1] > def f = (a -> a + x)
.:1:19 (to 1:20): Type error: cell inaccessible here: x
x + 1 here only makes sense as the value of another cell; you can’t use it in a def expression as the value of a variable, even a function.
Sometimes, though, we want to work with a cell in the abstract – that is, we want to work with a cell without creating a new cell or spreadsheet dependency. For example, the meaning of the function f above doesn’t actually depend on the value of the cell x, just that it’s a cell.
[1] > def link_adder = ((lnk, n) -> contents(lnk) + n)
link_adder : link(data)[in] -> data -> data
[1] > var cell i = 1
i : data
[1] > let plusi = link_adder(link(i)); plusi(5)
6
Here, link_adder is defining a function that depends on a cell (at evaluation time), but isn’t creating any new cells or spreadsheet logic.
A “real world” example might be a module with some configuration data in an in cell, and some helper functions to update some other data based on the config. Suppose we want a function like:
[1] > var cell config = {style: "yellow"}
[1] > def add_default_style(view) = if (view.style?) view else view + {style: config.style}
.:1:86 (to 1:98): Type error: cell inaccessible here: config
We’re not trying to create a new spreadsheet cell, just a function that depends on config. With a link we can do it:
[1] > def add_default_style(view) = ((config_lnk, view) -> if (view.style?) view else view + {style: contents(config_lnk).style})
add_default_style : link(data)<var> -> data -> data
[1] > let with_style = add_style(link(config)) in with_style({label: "hello world"})
{ "style": "yellow", "label": "hello world" }
I’m not quite sure why, but you still can’t really use links in a def expression because there’s no way to create one without referring to a cell:
[1] > def link_adder = ((lnk, n) -> contents(lnk) + n)
link_adder : link(data)<var> -> data -> data
[1] > var cell i = 1
i : data
[1] > def iplus1 = link_adder(link(i), 1)
.:1:25 (to 1:32): Type error: cells inaccessible here
[1] > def icontents = contents(link(i))
.:1:26 (to 1:33): Type error: cells inaccessible here
It seems to me like link(c) should be okay in a def, but perhaps I’m missing something.