Chapter: Introduction

i downloaded the xrnx starter pack html files: https://xrnx.googlecode.com/files/XrnxStarterPack270.zip

then unzipped that file and opened the file “! Introduction.txt.html” in my web browser (it’s in XrnxStarterPack270\Documentation\html\ )

so…

since this is Da Sandbox, i’ll just plunge into that Introduction chapter and report in this thread what i don’t quite understand (what needs further investigation)

stay tuned…

ok, the first thing i’ve tested is to copy-paste this to the lua terminal and execute it:

  
renoise.app():show_status("Status Message")  
  

i changed that string “Status Message” to see if it could display all kinds of characters, seems like there are no restrictions there

  
renoise.app():show_status("ÅÄÖ")  
  

how cute!

look mom, i can change the renoise status message at the bottom left of the renoise application itself

allright, but what else is there in that renoise.app() drawer?

so i tried to feed the terminal prompt with this:

  
oprint(renoise.app())  
  

and it results in this output:

  
>>> oprint(renoise.app())  
class: Application  
 properties:  
 active_clipboard_index  
 current_song  
 installed_tools  
 log_filename  
 recently_loaded_song_files  
 recently_saved_song_files  
 window  
 methods:  
 __STRICT  
 install_tool  
 load_song  
 new_song  
 new_song_no_template  
 open_path  
 open_url  
 prompt_for_filename_to_read  
 prompt_for_filename_to_write  
 prompt_for_multiple_filenames_to_read  
 prompt_for_path  
 save_song  
 save_song_as  
 show_custom_dialog  
 show_custom_prompt  
 show_error  
 show_message  
 show_prompt  
 show_status  
 show_warning  
 uninstall_tool  
  

so obviously there are some more stuff in that renoise.app() drawer

ok, but how can i learn more about the syntax required by each of these?

for example, i could write

  
renoise.app():show_status("Status Message")  
  

but how am i supposed to know that the show_status function needs that (“Status Message”) attached to it??

i need to explore this further… maybe there is some way to find out

i can see that there is a reference list of “all available Lua functions and classes that control the Renoise application” in the chapter titled “Renoise Application API Reference”

( XrnxStarterPack270\Documentation\html[b]Renoise.Application.API.lua.html[/b] )

but this is not what i meant by the question in the quote above

rather i wonder if there is a way to get more information about a function and its parameters directly at the terminal prompt

Would it be fair to say that typically an API assumes some familiarity with the programming language it is based around. IE you would have to study LUA itself, not Renoise’s API, to get the syntax and relationship before Functions, Classes, Observables, Functions etc. It is not the API’s job to teach you how to correctly write an If/Else loop (if they exist for example) but to tell you what of the existing LUA library has been implemented and what functions there are to interact with Renoise.

yes, that would probably be fair :)

however, as i’m reading the docs for the first time, i’ll just try out things as i read, to get a first impression and basic frame of reference before i plunge into the Lua specifics

often it’s fruitful for me to simply dive into something and experiment, while investigating things on the go (looking up concepts, reading about Lua syntax, etc)

@.xrns: i appreciate your efforts, and i think it is a good way to start this exploration, as it would probably be the way most would start out doing this stuff. funny thing is how fast it branches out into different questions. for example, i started out the same way you did, but never really tried the oprint() thingy to see the other options. so essentially you’re documenting your own road through the documentation, but it does not matter, it is still very useful.

@kazakore: if you had not said it, i would have. completely true. but it might be a good idea to mention this somewhere on the http://scripting.renoise.com site as well. the way it is stated there, it seems you never need to bother with the lua docs, which turns out not to be true (in most cases).

ok, something that is not very clear to me:

The API is object-oriented, and thus split into classes.  

why? if it is object-oriented, wouldn’t it logically be split into objects?

An an object is an instance of a class.

Psuedo example:

  
-- Class  
class "Person"  
function Person:__init(name)  
 self.name = name  
end  
function Person:eat()  
 print(self.name .. " is eating cake.")  
end  
  
-- Objects  
p1 = Person("Jane")  
p1:eat()  
  
p2 = Person("Joe")  
p2:eat()  
  
--[[ Output  
Jane is eating cake.  
Joe is eating cake.  
]]--  
  

The Class is the blueprint, the Object is the real thing. (there are exceptions, eg static methods, singletons, …, but that’s not beginner stuff)

The API is split into Classes. You the programer make Objects out of Renoise Classes and do something with them.

Cheers.

thanks a lot Conner, very clear to me now. Class == Generic Object; Object == Object. glad you took the time to explain this.

And from that I take it “_init()” are the initial parameter(s) you must give when defining a new object within a Class, correct?

so…

  
-- Class  
class "Person"  
function Person:__init(name,sex)  
 self.name = name  
 self.sex = sex  
end  
function Person:what()  
 print(self.name .. " is " .. self.sex)  
end  
  
-- Objects  
p1 = Person("Jane","female")  
p1:what()  
  
p2 = Person("Joe","male")  
p2:what()  
  
--[[ Output  
Jane is female.  
Joe is male.  
]]--  
  

right?

i observe that in this pseudocode example, the same name “Person” is following both the words “class” and “function”

i guess that’s mandatory, so that for example one can’t write it like this instead:

  
-- Class  
class "Person"  
function X:__init(name)  
 self.name = name  
end  
function Y:eat()  
 print(self.name .. " is eating cake.")  
end  
  

another thing i observe is in that first function, self.name = name

so for example one can’t have it like this ?

  
-- Class  
class "Person"  
function Person:__init(name)  
 self.x = name  
end  
function Person:eat()  
 print(self.x .. " is eating cake.")  
end  
  

@.xrns: functions need to be placed ON objects, attached to them, so to speak… that is why you get the OBJECT:FUNCTION() construction. as Conner explained earlier, a Class is the blueprint for an object. so, he uses the ‘class’ command to make a new object called ‘person’, and attaches a function to it.

‘self’ refers to the object. so instead of ‘self.name’ you could also write ‘Person.name’ i suppose. again, the property is attached to the object, so OBJECT.PROPERTY … but ‘self’ is a shortcut by which the object refers to, well, itself.

take a look at my example with 2 arguments. i think you can do ‘self.x = name’ no problem. unless i missed something and you can only do self.SOMETHING if .SOMETHING exists as a property on the Blueprint Class?

No, you can have an example like this. Nothing wrong with the above. Just hard to remember x.

Imagine doing:

  
oprint(renoise.app())  
  

and it results in this output:

  
>>> oprint(renoise.app())  
class: Application  
 properties:  
 x  
 y  
 z  
 methods:  
 a  
 b  
 c  
  

Not very useful to others…

good point, Conner! :)

i also noticed by testing that the class name doesn’t need to be the same as the functions in that class (just to answer myself earlier in this thread)

so it’s perfectly fine to have:

  
class "Fruitcake"   
function Fruit:__init(name,color)   
 Fruit.name = name   
 Fruit.color = color   
end   
function Fruit:what_color()   
 print(Fruit.name .. " is " .. Fruit.color)   
end   
  
f1 = Fruit("Apple","green")   
f1:what_color()   
  
f2 = Fruit("Banana","yellow")   
f2:what_color()   
  

and of course now i can use for example

  
oprint(f2)  
  

to get this information about that specific object:

  
class: Fruit  
methods:  
 __init  
 what  
 what_color  
  

nice!

EDIT: actually, it’s not as nice as i first thought because why does it return “class: Fruit” instead of “class: Fruitcake” ? i need to investigate this a bit further…

EDIT2: ok, seems like previous editing is retained in memory when testing things out in the terminal editor

actually i think i’m turning into fruitcake over this issue:

i shut down renoise just to get rid of everything global

then opened renoise again and started my TestPad.lua which consists of the following:

  
class "Fruitcake"   
function Fruit:__init(name,color)   
 Fruit.name = name   
 Fruit.color = color   
end   
function Fruit:what_color()   
 print(Fruit.name .. " is " .. Fruit.color)   
end   
  
f1 = Fruit("Apple","green")   
f1:what_color()   
  
f2 = Fruit("Banana","yellow")   
f2:what_color()   
  

now, running this results in the following error:

  
*** TestPad.lua:2: variable 'Fruit' is not declared  
*** stack traceback:  
*** [C]: in function '_error'  
*** [string "local mt = getmetatable(_G)..."]:29: in function   
*** TestPad.lua:2: in main chunk  
  

so i guess that i have to take back what i wrote above that class name and class functions don’t need to have the same name :)

conclusion: they must have the same name, it’s not enough that the functions are stacked up under the “class” marker

Almost. You are creating a Fruit object here… Not Fruitcake.

  
function Fruit:__init(name, color)  
  

Can’t declare class “Fruitcake” then start attaching methods to class “Fruit”

The rest is fine, though.

Right, exactly.

Sorry guys, i take it back. I wasn’t really looking attentively.

Incorrect:

  
class "Fruit"   
function Fruit:__init(name,color)   
 Fruit.name = name   
 Fruit.color = color   
end   
function Fruit:what_color()   
 print(Fruit.name .. " is " .. Fruit.color)   
end   
  
local f1 = Fruit('Apple', 'Red')  
local f2 = Fruit('Pear', 'Green')  
  
print(f1:what_color())  
-- Output is: Pear is Green  
  

Output is obviously wrong.

What we want is:

  
class "Fruit"   
function Fruit:__init(name,color)   
 self.name = name   
 self.color = color   
end   
function Fruit:what_color()   
 print(self.name .. " is " .. self.color)   
end   
  
local f1 = Fruit('Apple', 'Red')  
local f2 = Fruit('Pear', 'Green')  
  
print(f1:what_color())  
-- Output is: Apple is Red  
  

There’s difference between Fruit and self.

Self means assign the value to myself, where as fruit (sort of) means “assign the value to the blueprint, affect everyone”

Cheers.

Also notice in your above two example you have

f1.what_color in the first one
and f1:what_color in the second. (Notice the period and colon difference.)

Did they both actually work or is the first one a typo?

In the error you pointed out in the first one, will it always take the last defined Object of a Class if you use class name, rather than Self?

It was a typo, but it didn’t barf on me. I fixed it. As explained in another thread, colon is a shortcut.

I’m not sure. I would never write Lua like that. The behaviour falls under “unexpected” to me. In something like PHP it might be “static” but I’m not sure what it is in Lua.

This should also emphasize that you don’t have to know everything about a language to get work done. I don’t know everything, doesn’t stop me in the least.