locals can only be accessed in their own scope. (the chunk, file, or function that defined them.) the REPL has its own scope and in fact its own environment which shadows the global environment. so the downside of using local in scripts is that you simply can’t see those variables in the REPL.

the upside of using locals is that it is bad to pollute the global namespace from your script. specifically it can lead to two pitfalls, of which we’ve already seen plenty: 1) you can easily clobber vital global vars used by the nonrns system itself, possibly preventing norns from starting if you do this in the default script. 2) you can easily accidentally use globals defined in previously run scripts, leading to weird bugs and indeterminate behavior.

we’ve discussed sandboxing of scripts to make both these issues go away, and clear a path towards inspecting script variables from the REPL. see this issue:
https://github.com/monome/norns/issues/425
and this PR:
https://github.com/monome/norns/pull/436
and elsewhere.

we just need to commit to a solution and then revise all the existing scripts.

5 Likes

Some questions regarding Parameter Sets (as discussed in norns study 3):
I do have several tables in my script, whose values I’d like to store for later recall. From what I understood in study 3, in order to store a value in a parameter set, I first need to define a parameter (add_number) to which I assign the value. Does this mean that if I want to store a table, I do need to define a parameter for each value in the table? Or can a parameter be a table? If yes, how do the minimum/maximum/default values of the parameter definition work for a table?

I should mention that I am a complete novice at programming, and all that I am currently doing is trying to understand the AWAKE script, and modifying it step by step so that it does more of what I want…and I am really enjoying this feeling of embarking onto a new journey!

that’s one possible way of storing/recalling tables, but depending on the table and its content it may not be the most optimal one. what are you storing in your table?

no.

you might want to look at the playfair script which persists table content in a playfair.data file.

also read about table persistence in lua in general at https://www.lua.org/manual/2.1/subsection3_7_3.html.

i’m quite new to lua aswell.

imo, utility methods could be added to the norns framework to support these kinds of operations.

1 Like

@wolfgangschaltung FYI @jah is referring to the new version of playfair which is on github, not on release yet:

see the functions at the very bottom

2 Likes

@jah & @tehn: Thanks for your answers, these gave me quite something to chew on.

There are 2 tables (with integer numbers), and 4 integer numbers, the totality of which I want to store and recall as a preset (while the AWAKE sequence is running, without messing with the timing).

I understand that such a preset can be accomplished with nested tables inside the script, but when I send norns to sleep, everything will be gone, so I must find a way to write the contents of all presets I might create at runtime to disk to retrieve them later (e.g. after awakening norns).

Thanks, but I have to admit this is way over my head (I am not only new to Lua, but new programming at all). To name just 2 questions I had after reading it:

  • where do I specify the name for the text file that is generated?
  • how do I load the values stored in the text file? The text just said “In order to restore this value, a lua_dofile suffices.”, which left me rather puzzled.

Thanks much, while I am far from really understanding it, this looks way more explicit and thus comprehensible to me than the section from the Lua manual! I will try to work my way thru this during the next days, for now I will try to create the (volatile) preset management in AWAKE first.

Just 2 questions for now:

  • The code for the new PLAYFAIR ends with
cleanup = function()
  playfair_save()
  end

What does this mean? cleanup is not used anywhere else in the script, so when&how do these lines get executed?

  • What is the purpose of these require commands, and why are they sometimes put into variables?

require 'er'

engine.name = 'Ack'

local ack = require 'jah/ack'
local BeatClock = require 'beatclock'

Thanks much in advance!

by default, numbers in lua are represented as double-precision floating point (64 bits). so max value is approximately 1.8 x 10308.

with lua 5.3, you can also explicitly create variables of integer type using foo = int(555). this also uses 64 bits, giving the range [-9223372036854775808, 9223372036854775807].

for example

local foo = require 'foo'
foo.dosomething()

this is the recommended way to use code modules in lua (aka libraries.) require 'foo' looks for a module source named foo.lua. the assumption in this idiom is that foo.lua returns a table (here containing the dosomething() method.) if foo has previously been loaded by require, it returns a reference to this table; otherwise it executes foo.lua.

local foo = require 'foo' stores a local reference to foo. this is safer than polluting the global namespace for various reasons, and also allows you to name the local reference whatever you want. f = require 'foo'; f.dosomething() is also valid (in case you want to use the name foo for something else, or don’t want to type it, or whatever.)

more on modules in lua: http://lua-users.org/wiki/ModulesTutorial

if your script defines cleanup(), it will be executed by the script loading module when the next script is loaded.

[mod: i’m moving this to Norns:scripting]

3 Likes

Thanks much for the explanations, also for the link to lua-users.org!

I remember I read about it in the reference manual some days ago:
“Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them.”, but obviously I did not understand the consequences. Thanks much, I get it now!

Thanks for pointing me to this trick…another example where I forgot what I have read just a couple of days ago in norns study #2. I blame it on the excessive heat here in Germany :wink:

1 Like

Reading up the thread you are new to all this I see. Reference and value is easy to trip up on early on (& another good reason to stay away from copying things - it quickly gets you into language depths) when I start using a new language it’s something I look up very quickly.

The best advice I can give you from a life time of coding (nigh on 40 years - eek!) is don’t try and do fancy things. Go for straight forwards and obvious. And especially don’t take short cuts. So in this case copying and rotating are two separate things. So do them separately. I know the temptation is to think “oh I can do that in one step”. Resist. Future you will like now you much more :wink:

4 Likes

Thanks, I will try to follow your advice!

If I may ask one more question: With what you said in mind, what’s the recommended way when all I want to do is to make a 1:1 copy of a table into a different table, and all elements are numbers? From what I know right now, I’d probably still go with

for i = 1, #original do
copy[i] = original[i]
end

As long as the elements are always simple the you are good with that code (& in fact you can see in my recent Contribution to foulplay.lua in dust I made the exact same choice for the same reason)

Assumptions are what catch you out so consider making that assumption explicit in a comment but as long as it is you and your code making the table in the first place I wouldn’t worry

1 Like

Ok thank you, those are very useful informations.

as it happens, @Justmat just landed rotation for foulplay

https://github.com/monome/dust/pull/163

might be a handy jumping off point? (and maybe something we should consider moving to a shared library.)

1 Like

I had considered putting the rotate_pattern() function in lib/lua/er.lua, but wasn’t sure. :sweat_smile:

1 Like

:+1:

if/when you want to copy more than just numbers, you might find these reflections useful: http://lua-users.org/wiki/CopyTable

1 Like

Yeah, @Justmat and I talked about this when I hacked together that rotate function.

Would we want to throw a github pull request up for adding utility functions like this to the libraries?

3 Likes

+1 for (documented) additions to the library - much better to have single implementations of things that are well used (and therefore robust) and unless this kind of stuff goes in early you end up with all kinds of cut and paste or totally separate versions scattered throughout scripts…

1 Like

I agree, and especially in the case of rotate_pattern(). It seems like playfair could benefit from track rotation, as well as any other euclidean based scripts that come along in the future.

2 Likes

What about adding something like penlight to the available Lua modules?

Lua utility libraries loosely based on the Python standard libraries

GitHub, Lua Rocks, API docs.

It provides copy, deepcopy and others.

(Caveat: I’ve never used it, but the principle of adding a more full featured standard library to Lua seems sound for our use case.)

It might be better to think about blessing certain existing Lua libraries for inclusion rather than us trying to reinvent the wheel. There is a list of the most depended on Lua libraries here: https://luarocks.org/stats/dependencies

If there is interest I can open up a ticket on one of the GitHub issue trackers (probably norns).

5 Likes

Housekeeping for shapes drawn on grids and/or norns’s screen?

When doing my first steps in Lua with norns and grids, I wanted to
(a) draw shapes on the grid and
(b) interact with these grid shapes, i.e. detecting user pressing grid keys belonging to a shape, brightening or dimming a shape.

Being a rookie at this, I found that I have to do “double book-keeping” for this, i.e. I had to create (and maintain) these shapes in both function gridkey (x, y, z) and function gridredraw(). I found this to be error-prone, as I had to keep track of the coordinates of these shapes in both functions.

I guess I can overcome this by creating a function that simultaneously draws a shape and returns values if buttons belonging to a shape have been pressed.

Reading that the community is contemplating adding rotate_pattern() to the norns’s Lua library, does it make sense to add functions to norns’s Lua library that draw shapes onto the grid and/or norns’s screen? Or do these already exist and I just did not search for them thoroughly? Or is this double housekeeping expected?