One or two comments… Firstly, on reflection I’m not convinced that any kind of “house style” is necessary or desirable at this stage; it’s more healthy to see variations and combinations of styles in creative coding, especially if (getting all Sapir-Whorf here) variations lead to interesting musical applications. It’s not as if we have large dev. teams working on mission-critical enterprise apps. (For norns internals and OS-level tools, different rules probably apply.)
Secondly, I’m not a massive OOP fan despite (or perhaps because of) having done quite a bit of heavyweight Java development in the past, and a reasonable amount of C++ and Python (and a smattering of Ruby). The accidental aliasing risk is too great beyond a certain level of complexity (so, I’m not against OOP with immutable data, which seems to work well). By preference I’m more full-on functional, and spend a lot of time in Clojure. If Lua had a good performative immutable data library I might well go that way instead - there are so many benefits.
But I’m also fine with simplicity (despite my occasional tendency to over-engineer); while I’m going OOP for this app, it doesn’t look like it needs inheritance since it’s clearer to just monkey-patch in the virtual methods.
Object Orientation isn’t a panacea. It’s really exciting when you first discover it. After a bit you realise everything isn’t an object. Take the canonical example - yes your teapot and kettle and cup ARE objects but making a cup of tea is a process and if you start introducing the “visitor pattern” you deserve everything you get ;-). There is a reason every codebase you have ever worked on has a “utils” class/module/library/package
like @cassiel if I was being forced into someones paradigm - and I’ve spent enough time in my life torturing code to make it fit in bloody paradigms - then I’d go functional too at this stage of my life
anyway this is all moot. It’s hard enough to enforce coding standards let alone styles with a paid team who all have time allocated to code reviews and a process and a reason to all adhere to the standards and automation to help enforce it. Good luck with a bunch of creative people who do it for fun and actually aren’t sharing a lot of code
On 1: When I teach OOP I give my students a task to build a car and then remove one wheel. They are rather taken aback when all the wheels fall off. Also, in my experience, objects breed frameworks, whereas FP tends to breed libraries.
On 3: We’re here to be creative and have fun, not earn paycheques in back-end dev. teams. Having said that, I’m still a big believer in unit tests…
Oh - totally random & marginally off topic suggestion.
I gave in and bought the latest Lua book (a mix of feeling guilty and being fed up with always having to navigate the website) - it’s much better than the one on the website - I’d say it is probably worth it. Also it covers things in a little more depth
Oh, and that’s the other thing I was going to say: tools trump language. Much as I love Clojure, we would have had some serious domestic arguments by now were it not for Emacs, the REPL, parenthesis-based editing, specifications, and so on. (It’s still not great for multi-file projects.) Java coding was enjoyable because Eclipse is so amazing - though that could be a trap obscuring OOP pitfalls. The norns web interface is a good solid piece of work: as sophisticated as it needs to be to do the job well, and no more.
part of my motivation in having norns use lua is that i wanted something that could be potentially as approachable as teletype (ie, for non-programmers) but also powerful enough to do more complex things.
so, on one end of the spectrum— i wanted someone to be able to have a half-page of code which sets up softcut in a particular way, maps some encoders or midi, and shows something musically helpful on the screen. maybe extend it with some tables for musical purposes… ie, everyone has their own sequencer. at this level the code functions more like a composition, in a sense.
but i also set a precedent for big complicated scripts that are more like tools and less like compositions (ie mlr). and these big scripts could possibly use some OOP effectively. but to be honest i’m rewriting mlr from scratch and still not bothering with OOP— it feels overkill.
but where it is more often needed is in the core libraries. so maybe this is a good moment to set out a request: from all the smart people in this thread, we’d happily welcome contributions to the core library. for example— when norns started, there was no concept of “parameters” and that grew over time. i’d like to find situations where the core libs can address basic recurring needs, so where possible user scripts can be as short as possible and leverage existing patterns.
that said, things like the param system don’t accommodate every need— and there’s a point where overbuilding that system has diminishing returns. it’s very easy to make a custom param-menu-like thing… because it’s lua.
ps. the scripting docs (particularly the libs) are in desperate need of an overhaul, and a vision towards it. which will likely also suggest some sort of syntax unification… which is maybe what is meant by house style.
I think this kind of cookbook approach can really work & agree having off the shelf library components makes the creative lift of new ideas much easier
While not in anyway claiming to be “a smart person” - My Kria port has got a new output module which makes midi/crow output easier to shove into a script - I’d like to see how it goes down with people but if I get a positive response will submit it for consideration
Lua is indeed a good fit here - relatively simple out-of-the-box, but with the flexibility to be exploratory without being verbose. Sam Aaron went for Ruby with Sonic Pi for a similar reason, I think, though the simplicity there is a bit more syntactic: play 60 and you’re away.
Regarding the core library… well, FWIW shado is now up and running, though it needs a bunch of example apps and a push on the documentation. I’m not sure it’s quite ready to ship as a built-in component until it’s been stress-tested for performance.
There’s been a couple mentions of functional programming here, and I’m a fan of it too. It’d be nice to see some development of FP in the core library. Maybe developing the core lib deserves its on thread. Would be good to get some input on a couple things I want to contribute there.
Yeah… where to draw the line. Penlight looks impressive, but also quite heavy, and part of the appeal of norns for me is that it’s carrying a payload which does what’s needed to provide an integrated environment and nothing more - it’s lean.
Agree. The question that needs to be asked is ‘what problem are we solving?”
The ‘issues’ I have had are: clock sync/link - now solved, can’t be bothered writing things over & over - mostly output - I have my own solution for that. I also wondered today if some thing like teletypes faders & buttons might make sense? Params could do dynamic updating for slightly nicer UX
And that’s about it. Don’t need a lot else. All that is Norns specific too
Adding stuff to the base software stack is much easier than removing it so there has naturally been a healthy amount of debate around adding dependencies like penlight or even leveraging luarocks. I look at stuff like penlight and think:
is this something we want to carry forever as a dependency?
does it promote / foster implementations that are liable to work well in the embedded lua environment which matron provides?
does it provide something which cannot be achieved easily or by other means?
is it something that helps or hinders someone new to the platform or to coding?
is it something which helps or hinders one’s ability to share scripts among the community?
is there any risk that adding the dependency could increase support load on the core collection of folks fostering the platform today.
I’ve personally gone back and forth on this several times while debating myself. In the end I usually found myself coming back to:
penlight to me looks like a mixed bag, some good, some not so good. The higher order functions are the few things that I could see myself using but those are also readily had with passing functions/closures into existing iteration mechanisms. I’m generally a fan of functional programming but I also expect/want a solid immutable collection library to go with it and an optimizing compiler to eliminate all of the intermediate garbage when using it in an environment which is soft real time.
Of late there has been more energy around building/expanding the core library in ways which are broadly applicable across the types of scripts people are generating.
All that said I do occasionally install stuff locally just to try it out and experiment (or pull it into the lib/ space for whatever script I’m working on). For code/scripts which one doesn’t intend to share there is little downside.
Ah, the MIT disease of incorporating every feature and option. Perhaps we should be thankful that the norns cannot (yet) function as an email client.
The lowest-impact route for new code is is probably to keep letting people roll stuff out as top-level script libraries. Scripts can refer to one another, and the main loadable script can serve as a demo. (The script downloader doesn’t do dependency analysis, but taking that task on probably means, well, reimplementing luarocks.)
This is a bit of an aside, but: as a very minor feature upgrade, would there be any support for something like .gitignore for sub-directories of scripts? I want to roll out a script which itself scans a subdirectory for other scripts, none of which is directly runnable. Right now everything appears.
Alternatively - house style? - should everything actually be somewhere under lib? As I think about it, I’m not averse to lib/something for “internal” coding, so may just refactor to that.
There’s probably a better way to do it, but what I’ve basically done is to have my class constructor take a table of options that set all of its properties. When I save it, I use tab.save, and when I load it, I pass the loaded table to the constructor again and overwrite my instance with a new one.
Sounds convoluted as I type it, but hopefully makes sense…
sort of like:
local instance = MyObject.new(options)
local loaded = tab.load(path)
instance = MyObject.new(loaded)