Intro
I've noticed a substantial amount of people wondering how variables are managed in Decker, so I thought it might be helpful to start a write-up about some of the patterns I've been using to create, store, and edit variables in both a global and local environment.
For those just starting out - don't be too intimidated by the length of these scripts; Most have been made longer with intentional spacing / comments. It's always been a difficult task to write things that are both concise and informative, but I'll do my best!
Creating Global Variables
If you're already familiar with Lil operations, you'll know that It's possible to store a string within a field, and access it locally via 'fieldname.text' or globally with the exact path: 'cardname.widgets.fieldname.text'. In Decker, it's standard practice to store data within widgets using their .attributes. However, if you're working on a larger project with a lot of variables, it might be helpful to keep everything within a single widget and make sure it can be accessed from anywhere using a name of your choice. Now, how can we set that up?
First, create a grid widget on any card. I'll be using 'grid1' on the 'home' card, populated with a few dummy variables:
{"fruits":[{0:"apple",1:"orange"}],"cats":[{0:"siamese",1:"tabby",2:"calico"}],"flag":[1]}

Next, we'll visit the deck script to add this line:
_G:home.widgets.grid1.value
In this context, '_G' is the name of the variable we're assigning our grid value to - any space-less string will work here.
Now from anywhere in our deck, we can type '_G.fruits' into the Listener and get '({0:"apple",1:"orange"})'. However, this arrangement isn't ideal, because these variables are returning as a (list), indicated by the surrounding parenthesis. Since this affects scope, we'd need to type '_G.fruits[0][0]' instead of '_G.fruits[0]' to return "apple", and there's currently no way to change these values unless we edit the grid directly.
Luckily, we aren't done yet; In the following section I'll show you how to create get[] and set[] functions, to serve as wrappers for viewing and adding new data.
'get' and 'set' Functions
Let's return to the deck script and redefine '_G' so that it refers to the grid itself, instead of the value it stores:
_G:home.widgets.grid1
In the same area, we'll start adding a few lines of code. The get[] function will return the value of the variable we look up, using the _G namespace to refer to the grid widget we populated earlier, and set[] will assign a value to a variable within a given table.
Here's a small setup for both functions, with a few comments (starting with #) for clarity:
# usage: get[_G "varname"]
on get x y do
x.value[y][0]
# return the variable y from table x
end
# get[_G "flag"] will return 1
# usage: set[_G "varname" value]
on set x y z do
r: cols x.value
# create a variable called r, comprised of the column data from x
x.value: table r[y]:z
# set the value of x to a new table where the variable y is changed to reference z, and return it.
end
Assuming we don't want to bloat up our global table with unused values, we can add another function to the end of set[] to cull nil values:
on set x y z do r:cols x.value x.value:table r[y]:z cullnil[x] end
# the set[] function from above, condensed into a single line, with 'cullnil[x]' added
on cullnil x do
r:() dict ()
# create a new empty dictionary called r
each v k in cols x.value
# cycle through entries in table x, by column
# copy all existing variables from x to r
if v[0]
r[k]:v
end
end
# return r as a table
table r
end
If you've followed along this far, try setting a variable using the Listener, and retrieve it using get[]! If you aren't sure how you can interact with something, the 'typeof' operator will tell you what type of data it is. Given the context of our dummy variables, 'get[_G "cats"][1]' will return "tabby", because it's a numbered dictionary. If you want to add an entry to that dictionary, we'd need to retrieve and edit the variable, like so:
d:get[_G "cats"] d[count d]:"tuxedo" set[_G "cats" d]
We've now created a place to store our global variables, and the functions needed to access them, but a few cases still might find 'global' variables unsuitable. What if you have identically named variables that need to be unique across cards? In that case, it might be wise to limit the scope of your data by...
Going Local!
Grids can also store data on a per-card basis, if they share a name. The deck script will run every time a card is visited, so the following line will assign '_v' to the grid widget named 'vars', if it exists.
_v:deck.card.widgets["vars"]
The get[] and set[] functions work as they would with the global variable table, except by using '_v' instead of '_G'. If the grid doesn't exist, isn't named "vars" or the variable hasn't been defined, get[] will return nil.
















