Chapter: Introduction

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.

Yeah I was trying to find that again to reread to see if it made clearer to me. From the statement it seemed that with the period it should work, as I assume the function works on the entries in the Table.

IE:
(f1:what_color()) == (xx.what_color(f1))

So you could do: (colours.what_colour(f1, f2)) and get both outputted correct?

Also I also assume the print command is obsolete as there is print within the function itself?

Really should get scripting up and running but not on the right computer at the moment so pushed back to asking questions, rather than experimenting…

Yes, redundant.

Not my best work ;)

Think maybe this paragraph from the Editor_Terminal.txt should be mentioned earlier and a little more prominant and it took me a while to work why Execute just seemed to save the file, rather than run it, and I had to copy and past the whole load into the command line.

(PS. Obviously I’ve not got Renoise fired up here ;) )

My answer to that from experiments is a yes and a no!

Try using xx and it wont work as it has not been defined.

Use f1, f2 or Fruit and all will work fine. Seems as long as the variable before the period exists it will process the function with the value in the table field. Although, especially for reasons before, you’re best to keep the same or just use the colon.

Change colours to Fruit (as above it needs to know the variable (seems to say "variable not defined but works whether you put a class, object or variable in there) to work.)

But then no matter what I do it only ever seems to output the first argument (is that the right word? Or is it a table entry?) within the brackets().

Surely there is a way to do this? Or to run a function on all objects within a class? So if you add or remove objects you don’t need to do so much other editing of the script.

I’m guessing it’s more of these global class/definition such as the self one demonstrated above. Whereabouts are these documented?