Difference between revisions of "User:SuzannaLinn Resident/LuaLanguage2"

From Second Life Wiki
Jump to navigation Jump to search
Line 4: Line 4:


Remember that this is a quick overview to see what is new. Each one of the next scripts will require one or two classes to explain its content properly.
Remember that this is a quick overview to see what is new. Each one of the next scripts will require one or two classes to explain its content properly.


== Tables as lists of lists ==
== Tables as lists of lists ==
Line 39: Line 40:




== Functions, parameters and returns / functions, anonymous functions ==
== Functions, parameters and returns ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
-- Functions, parameters and returns
 
function calculate(a, b)
    return  a + b, a * b
end
 
local add, mul = calculate(10, 5)
print("Sum:", add)      -- Sum: 15
print("Product:", mul)  -- Product: 50
 
 
function calculate(a, b, ...)
    local addition = a + b
    local product = a * b
 
    for i = 1, select("#", ...) do
        local value = select(i, ...)
        addition = addition + value
        product = product * value
    end
 
    return addition, product
end
 
local add, mul = calculate(10, 5, 2, 3)
print("Sum:", add)      -- Sum: 20
print("Product:", mul) -- Product: 300
</syntaxhighlight>
</syntaxhighlight>
|
<syntaxhighlight lang="lsl2" line>
llSay(0,"hello");
</syntaxhighlight>
|}
Let's look at the left part of the slide in the viewer.
Functions can return several values, lines 3-9, two in this case, in line 4. The result is assigned to "add" and "mul" in line 7.
Functions can return several values, lines 3-9, two in this case, in line 4. The result is assigned to "add" and "mul" in line 7.


Line 64: Line 82:
In line 17 we get each parameter by its number of position in the ..., as usual in Lua starting with 1, not 0.
In line 17 we get each parameter by its number of position in the ..., as usual in Lua starting with 1, not 0.


Let's move to the right part.


== Functions, anonymous functions ==
<syntaxhighlight lang="lua" line copy>
-- Functions, anonymous functions
fruits = {"apple", "orange", "banana", "grape", "pear"}
table.sort(fruits, function(a, b)
    return a > b
end)
for i, fruit in ipairs(fruits) do
    print(fruit) -- pear / orange / grape / banana / apple
end
totalCalls = 0
table.sort(fruits, function(a, b)
    totalCalls = totalCalls + 1
    return #a < #b
end)
for i, fruit in ipairs(fruits) do
    print(fruit) -- pear / grape / apple / orange / banana
end
print(totalCalls)  -- 10
</syntaxhighlight>
We are sorting a table in two different ways, lines 6-12 and 15-26.
We are sorting a table in two different ways, lines 6-12 and 15-26.


Line 81: Line 127:




== Closures / for and iterators ==
== Closures ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
-- Closures
 
function createCounter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end
 
counter1 = createCounter()
counter2 = createCounter()
 
print( counter1() ) -- 1
print( counter1() ) -- 2
print( counter2() ) -- 1
print( counter1() ) -- 3
print( counter2() ) -- 2
</syntaxhighlight>
</syntaxhighlight>
|
LWe have a function that makes a counter, lines 11-12. Each time that it's called, lines 14-18, the counter is increased.
<syntaxhighlight lang="lsl2" line>
llSay(0,"hello");
</syntaxhighlight>
|}
Let's start with the left side and see what is a "closure".
 
We have a function that makes a counter, lines 11-12. Each time that it's called, lines 14-18, the counter is increased.


Let's look at lines 3-9.
Let's look at lines 3-9.
Line 118: Line 172:
Lua has three scopes of variables: globals, locals and closures, which are somewhere in the middle of the other two.
Lua has three scopes of variables: globals, locals and closures, which are somewhere in the middle of the other two.


== For and iterators ==
<syntaxhighlight lang="lua" line copy>
-- For and iterators
local function fibonacciIterator(limit)
    local a, b = 0, 1
    local count = 0
    print("I'm called")  -- "I'm called" is only printed once
    return function()
        if count >= limit then
            return nil
        end
        local nextNumber = a
        a, b = b, a + b
        count = count + 1
        return nextNumber
    end
end
for number in fibonacciIterator(10) do
    print(number)  -- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
end
</syntaxhighlight>
Let's move to the right of the slide.
Let's move to the right of the slide.


Line 136: Line 215:


== Metatables and metamethods ==
== Metatables and metamethods ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
-- metatables and metamethods
</syntaxhighlight>
 
|
function createReadOnlyTable(data)
<syntaxhighlight lang="lsl2" line>
    local mt = {
llSay(0,"hello");
        __index = data,
        __newindex = function(t, key, value)
            print("Not allowed to set key "..key.." to "..value)
        end
    }
    return setmetatable({}, mt)
end
 
readOnlyFruits = createReadOnlyTable( {"apple", "banana", "cherry", "pear"} )
 
readOnlyFruits[2] = "orange"  -- Not allowed to set key 2 to orange
readOnlyFruits[5] = "grape"  -- Not allowed to set key 5 to grape
 
print( readOnlyFruits[2] )  -- banana
print( readOnlyFruits[5] ) -- nil
</syntaxhighlight>
</syntaxhighlight>
|}
Now we are going to see how to make a read only table using a metatable.
Now we are going to see how to make a read only table using a metatable.


Line 166: Line 256:


== Objects ==
== Objects ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
-- Objects
 
Vector = {}
Vector.__index = Vector
 
function Vector.new(x, y, z)
    local self = setmetatable({}, Vector)
    self.x = x
    self.y = y
    self.z = z
    return self
end
 
function Vector.__add(v1, v2)
    return Vector.new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
end
 
function Vector.__sub(v1, v2)
    return Vector.new(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
end
 
function Vector.__mul(v1, v2)
    if type(v2) == "number" then
        return Vector.new(v1.x * v2, v1.y * v2, v1.z * v2)
    else
        return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
    end
end
 
function Vector:__tostring()
    return "<"..self.x..", "..self.y..", "..self.z..">"
end
 
v1 = Vector.new(1, 2, 3)
v2 = Vector.new(4, 5, 6)
 
print("v1:", v1)  -- v1: <1, 2, 3>
print("v2:", v2)  -- v2: <4, 5, 6>
print("v1 + v2:", v1 + v2)  -- v1 + v2: <5, 7, 9>
print("v1 - v2:", v1 - v2)  -- v1 - v2: <-3, -3, -3>
print("v1 scaled by 2:", v1 * 2)  -- v1 scaled by 2: <2, 4, 6>
print("Dot product of v1 and v2:", v1 * v2) --  Dot product of v1 and v2: 32
</syntaxhighlight>
</syntaxhighlight>
|
<syntaxhighlight lang="lsl2" line>
llSay(0,"hello");
</syntaxhighlight>
|}
Time for the objects. Both sides of the slide are the same script.
Time for the objects. Both sides of the slide are the same script.


Line 202: Line 326:


== Objects and inheritance ==
== Objects and inheritance ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
-- Objects and Inheritance
</syntaxhighlight>
 
|
Shape = {}
<syntaxhighlight lang="lsl2" line>
Shape.__index = Shape
llSay(0,"hello");
function Shape:new(x, y)
    local instance = setmetatable({}, self)
    instance.x = x or 0
    instance.y = y or 0
    return instance
end
function Shape:getPosition()
    return self.x, self.y
end
 
Circle = setmetatable({}, { __index = Shape })
Circle.__index = Circle
function Circle:new(x, y, radius)
    local instance = Shape.new(self, x, y)
    setmetatable(instance, self)
    instance.radius = radius or 1
    return instance
end
function Circle:getRadius()
    return self.radius
end
function Circle:getArea()
    return math.pi * self.radius^2
end
 
Rectangle = setmetatable({}, { __index = Shape })
Rectangle.__index = Rectangle
function Rectangle:new(x, y, width, height)
    local instance = Shape.new(self, x, y)
    setmetatable(instance, self)
    instance.width = width or 1
    instance.height = height or 1
    return instance
end
function Rectangle:getWidth()
    return self.width
end
function Rectangle:getHeight()
    return self.height
end
function Rectangle:getArea()
    return self.width * self.height
end
 
myCircle = Circle:new(10, 20, 5)
print(myCircle:getPosition())  -- 10 20
print(myCircle:getRadius())    -- 5
print(myCircle:getArea())      -- 78.539816339745
 
myRectangle = Rectangle:new(15, 25, 4, 6)
print(myRectangle:getPosition())  -- 15 25
print( myRectangle:getWidth())    -- 4
print(myRectangle:getHeight())    -- 6
print(myRectangle:getArea())     -- 24
</syntaxhighlight>
</syntaxhighlight>
|}
Let's go to inherit objects. Both sides of the slide are the same script.
Let's go to inherit objects. Both sides of the slide are the same script.


Line 224: Line 398:


== Objects and multiple inheritance ==
== Objects and multiple inheritance ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
Color = {}
</syntaxhighlight>
Color.__index = Color
|
 
<syntaxhighlight lang="lsl2" line>
function Color:new(r, g, b)
llSay(0,"hello");
    local instance = setmetatable({}, self)
    instance.r = r or 0
    instance.g = g or 0
    instance.b = b or 0
    return instance
end
 
function Color:setColor(r, g, b)
    self.r = r
    self.g = g
    self.b = b
end
 
function Color:getColor()
    return self.r, self.g, self.b
end
 
function Color:getColorFormat()
    return "R:"..self.r.." G:"..self.g.." B:"..self.b
end
</syntaxhighlight>
</syntaxhighlight>
|}
Multiple inheritance is also possible.
Multiple inheritance is also possible.


It's recommended to design our structure of classes in a way that we don't need multiple inheritance, but if we need it, we can use it.
It's recommended to design our structure of classes in a way that we don't need multiple inheritance, but if we need it, we can use it.


We are adding a new class Color, at left of the slide.
We are adding a new class Color.


At right we have the class ColoredCircle, that inherits from Circle and Color.
<syntaxhighlight lang="lua" line copy>
ColoredCircle = {}
ColoredCircle.__index = function(tbl, key)
    return tbl.Circle[key] or tbl.Color[key]
end
 
function ColoredCircle:new(x, y, radius, r, g, b)
    local instance = {
        Circle = Circle:new(x, y, radius),
        Color = Color:new(r, g, b)
    }
    setmetatable(instance, self)
    return instance
end
 
myColoredCircle = ColoredCircle:new(25,25,10, 255, 128, 64)
 
print(myColoredCircle:getPosition())    -- 25 25
print(myColoredCircle:getRadius())      -- 10
print(myColoredCircle:getArea())        -- 314.15926535898
print(myColoredCircle:getColorFormat())  -- R:255 G:128 B:64
</syntaxhighlight>
We have the class ColoredCircle, that inherits from Circle and Color.


This script should have the classes Color and Circle (and Shape) in the same script to work. I'm not copying them to avoid repeating.
This script should have the classes Color and Circle (and Shape) in the same script to work. I'm not copying them to avoid repeating.
Line 250: Line 462:


== Error handling ==
== Error handling ==
{| {{KBtable}}
|
<syntaxhighlight lang="lua" line copy>
<syntaxhighlight lang="lua" line copy>
print(a)
function calculateSquareRoot(number)
</syntaxhighlight>
    return math.sqrt(number)
|
end
<syntaxhighlight lang="lsl2" line>
 
llSay(0,"hello");
function safeSquareRoot(input)
    local success, result = pcall(calculateSquareRoot, tonumber(input))
 
    if success then
        print("The square root is:", result)
    else
        print("Error occurred:", result)
    end
end
 
safeSquareRoot(25)      -- The square root is: 5.0
safeSquareRoot("hello") -- Error occurred: main.lua:2: bad argument #1 to 'sqrt' (number expected, got nil)
safeSquareRoot(100)      -- The square root is: 10.0
</syntaxhighlight>
</syntaxhighlight>
|}
|}

Revision as of 01:18, 1 October 2024

The language: Lua beyond LSL

Standard Lua and Luau have some differences. Most of the next code runs in both of them. I'm using "Luau" at the end of the comment in the first line for Luau only code.

Remember that this is a quick overview to see what is new. Each one of the next scripts will require one or two classes to explain its content properly.


Tables as lists of lists

-- Tables as lists of lists (Lua)

fruitData = {
    { name = "Apple", quantity = 50, color = "Red", season = "Fall" },
    { name = "Banana", quantity = 30, color = "Yellow" },
    { name = "Cherry", quantity = 20, color = "Red" },
    { name = "Orange", quantity = 10, color = "Orange", organic = true }
}

for index, fruit in pairs(fruitData) do
    print("Fruit #" .. index)
    print("Name: " .. fruit["name"])
    print("Quantity: " .. fruit["quantity"])
    print("Color: " .. fruit["color"])
    if fruit["season"] then
        print("Season: " .. fruit["season"])
    end
    if fruit["organic"] then
        print("Organic: " .. tostring(fruit.organic))
    end
    print()
end

Here we have an array of tables, a "list of lists".

Each table in the array can have the same elements, or different, or different quantity of elements.

The "for" loops on the array. We get the value of each element using its key, between [ and ].

In line 15, or 18, if the key doesn't exist in the table, "nil" is returned. A "nil" in a condition is false.


Functions, parameters and returns

-- Functions, parameters and returns

function calculate(a, b)
    return  a + b, a * b
end

local add, mul = calculate(10, 5)
print("Sum:", add)      -- Sum: 15
print("Product:", mul)  -- Product: 50


function calculate(a, b, ...)
    local addition = a + b
    local product = a * b

    for i = 1, select("#", ...) do
        local value = select(i, ...)
        addition = addition + value
        product = product * value
    end

    return addition, product
end

local add, mul = calculate(10, 5, 2, 3)
print("Sum:", add)      -- Sum: 20
print("Product:", mul)  -- Product: 300

Functions can return several values, lines 3-9, two in this case, in line 4. The result is assigned to "add" and "mul" in line 7.

Functions can also have an indeterminate number of parameters, like in lines 12-27. The ... represents any quantity of parameters.

So the function in line 12 has from 2 to any number of parameters. We will use 4 in total in this example (line 25).

We use the system function "select" to get the parameters.

In line 16, "select" with "#" returns the quantity of parameters.

In line 17 we get each parameter by its number of position in the ..., as usual in Lua starting with 1, not 0.


Functions, anonymous functions

-- Functions, anonymous functions

fruits = {"apple", "orange", "banana", "grape", "pear"}


table.sort(fruits, function(a, b)
    return a > b
end)

for i, fruit in ipairs(fruits) do
    print(fruit) -- pear / orange / grape / banana / apple
end


totalCalls = 0

table.sort(fruits, function(a, b)
    totalCalls = totalCalls + 1
    return #a < #b
end)

for i, fruit in ipairs(fruits) do
    print(fruit) -- pear / grape / apple / orange / banana
end

print(totalCalls)  -- 10

We are sorting a table in two different ways, lines 6-12 and 15-26.

"table.sort" is a system function. Its first parameter is a table, the second parameter is a function that takes two values and returns "true" if the first value is to be placed before the second value in the sorted table.

A function in Lua is a type of data, like boolean, number, string or table.We can use functions as parameters, return functions, make a table of functions...

Functions don't need to have a name. As a parameter, we can use the name of a function, or the code of the function, like we are doing in lines 6-8. The function code goes from "function" to "end".

table.sort calls this function that we have sent to do the sorting.

In the second sort, lines 15-26, we are sorting by length of the fruit name, shorter fruits before.

And we have added a counter to see how many comparisons it needs.


Closures

-- Closures

function createCounter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end

counter1 = createCounter()
counter2 = createCounter()

print( counter1() ) -- 1
print( counter1() ) -- 2
print( counter2() ) -- 1
print( counter1() ) -- 3
print( counter2() ) -- 2

LWe have a function that makes a counter, lines 11-12. Each time that it's called, lines 14-18, the counter is increased.

Let's look at lines 3-9.

In line 4, the keyword "local" defines "count" as a local variable, otherwise it would be global.

In line 5, we don't return a value, but a function that increases "count" and returns it, lines 5-8.

The variables counter1 and counter2 contain functions,that are executed each time that we use them with ().

But the variable "count" is local. The function createCounter finished its execution when it returned the function that increases "count"...

So what variable "count" are counter1 and counter2 increasing and how is the value preserved between calls?

This is what is called a closure, or external local variable, or upvalue.

The returned function, by using "count", encloses the variable with itself. Each function that is returned has its own "count".

From the point of view of the function is like a global variable, and its value is preserved between function calls.

For the rest of the script is like a local variable of the function, so not accessible.

Lua has three scopes of variables: globals, locals and closures, which are somewhere in the middle of the other two.


For and iterators

-- For and iterators

local function fibonacciIterator(limit)
    local a, b = 0, 1
    local count = 0
    print("I'm called")  -- "I'm called" is only printed once

    return function()
        if count >= limit then
            return nil
        end
        local nextNumber = a
        a, b = b, a + b 
        count = count + 1
        return nextNumber
    end
end

for number in fibonacciIterator(10) do
    print(number)  -- 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
end

Let's move to the right of the slide.

We have seen the "for...in" with ipairs and pairs. Now we will use our own iterator.

An iterator is a function that is called by the "for...in" in each loop and returns a value. The "for" goes on until this function returns "nil".

In this example we iterate on fibonacci numbers. The parameter "limit" is how many numbers we want.

The function fibonacciIterator is called only once, when the "for" starts. What is called in each loop is the function returned by fibonacciIterator.

The iterator is the anonymous function in lines 9-17. It has 3 closures: a, b and count.

In line 14, the values on the right side of the = are all obtained before starting to assign them to the variables on the left.

For instance: a, b = b, a is a way to swap the values without using an intermediate variable.


Metatables and metamethods

-- metatables and metamethods

function createReadOnlyTable(data)
    local mt = {
        __index = data,
        __newindex = function(t, key, value)
            print("Not allowed to set key "..key.." to "..value)
        end
    }
    return setmetatable({}, mt)
end

readOnlyFruits = createReadOnlyTable( {"apple", "banana", "cherry", "pear"} )

readOnlyFruits[2] = "orange"  -- Not allowed to set key 2 to orange
readOnlyFruits[5] = "grape"   -- Not allowed to set key 5 to grape

print( readOnlyFruits[2] )  -- banana
print( readOnlyFruits[5] )  -- nil

Now we are going to see how to make a read only table using a metatable.

A metatable is a table that is linked to another table and has keys to control how the table works.

The main use of metatables are with classes and objects, but let's start with this less useful example.

The function createReadOnlyTable, lines 3-11, takes values for an array table and returns a table that can't be modified.

"mt", line 4, is the metatable. Its possible keys are predefined in Lua and start with __.

We are using __index, line 4, to assign the table where to access the data when we read it. In this case the table "data" in the parameters.

And __newindex, line 5, that has a function that executes when we write a new key to the table. In this a case a function that returns an error message.

In line 10, with the system function setmetatable, we assign the metatable to an empty table and return it.

After line 13, readOnlyFruits is a table, that has a metatable, that doesn't allow any new key and has a table, from which it obtains the values.


Objects

-- Objects

Vector = {}
Vector.__index = Vector

function Vector.new(x, y, z)
    local self = setmetatable({}, Vector)
    self.x = x
    self.y = y
    self.z = z
    return self
end

function Vector.__add(v1, v2)
    return Vector.new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
end

function Vector.__sub(v1, v2)
    return Vector.new(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
end

function Vector.__mul(v1, v2)
    if type(v2) == "number" then
        return Vector.new(v1.x * v2, v1.y * v2, v1.z * v2)
    else
        return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
    end
end

function Vector:__tostring()
    return "<"..self.x..", "..self.y..", "..self.z..">"
end

v1 = Vector.new(1, 2, 3)
v2 = Vector.new(4, 5, 6)

print("v1:", v1)  -- v1: <1, 2, 3>
print("v2:", v2)  -- v2: <4, 5, 6>
print("v1 + v2:", v1 + v2)  -- v1 + v2: <5, 7, 9>
print("v1 - v2:", v1 - v2)  -- v1 - v2: <-3, -3, -3>
print("v1 scaled by 2:", v1 * 2)  -- v1 scaled by 2: <2, 4, 6>
print("Dot product of v1 and v2:", v1 * v2)  --  Dot product of v1 and v2: 32

Time for the objects. Both sides of the slide are the same script.

We are creating an object "vector", lines 3-32. We will not need to do it, LuaSL will have vectors, it's only an example.

There is not an "object" type in Lua. Objects are created using metatables.

The class is a metatable that stores the functions (methods). The instance is a table that stores the values (properties) and has the class as metatable.

In our example, Vector is the class, v1 and v2 are the instances.

We start defining Vector as a table, line 3, with __index assigned to itself.

It means that when the instance doesn't find a key in its table (which will happen with the functions of the class), it will look for it in the Vector table (which has the functions).

The function "new", lines 6-12, is the constructor. We could use any name for it, but "new" is the usual one.

It returns a new table, with Vector as metatable, and the initial values.

In lines 14-28 we are defining operators for the class, using __add, __sub and __mul. There are more predefined keys for other operators.

It's not possible to overload operators, so with __mul we check the type of the parameter in line 23 to calculate Vector*number (returning a vector) or Vector*Vector (returning a number).

In lines 30-32 we define __tostring that is called when a conversion to string is needed, like in the "print" function.


Objects and inheritance

-- Objects and Inheritance

Shape = {}
Shape.__index = Shape
function Shape:new(x, y)
    local instance = setmetatable({}, self)
    instance.x = x or 0
    instance.y = y or 0
    return instance
end
function Shape:getPosition()
    return self.x, self.y
end

Circle = setmetatable({}, { __index = Shape })
Circle.__index = Circle
function Circle:new(x, y, radius)
    local instance = Shape.new(self, x, y)
    setmetatable(instance, self)
    instance.radius = radius or 1
    return instance
end
function Circle:getRadius()
    return self.radius
end
function Circle:getArea()
    return math.pi * self.radius^2
end

Rectangle = setmetatable({}, { __index = Shape })
Rectangle.__index = Rectangle
function Rectangle:new(x, y, width, height)
    local instance = Shape.new(self, x, y)
    setmetatable(instance, self)
    instance.width = width or 1
    instance.height = height or 1
    return instance
end
function Rectangle:getWidth()
    return self.width
end
function Rectangle:getHeight()
    return self.height
end
function Rectangle:getArea()
    return self.width * self.height
end

myCircle = Circle:new(10, 20, 5)
print(myCircle:getPosition())  -- 10 20
print(myCircle:getRadius())    -- 5
print(myCircle:getArea())      -- 78.539816339745

myRectangle = Rectangle:new(15, 25, 4, 6)
print(myRectangle:getPosition())  -- 15 25
print( myRectangle:getWidth())    -- 4
print(myRectangle:getHeight())    -- 6
print(myRectangle:getArea())      -- 24

Let's go to inherit objects. Both sides of the slide are the same script.

Here we have a class "Shape" with a position (x,y). And two classes, "Circle" and "Rectangle", with area and some other properties, that inherits from it.

myCircle has Circle as metatable, and Circle has Shape as metatable.

When we call a function in myCircle, Lua looks for it in the table myCircle, then in the table Circle, and if it is not there, in the table Shape.

It looks slow, but it's optimized at compile time, and is very fast.


Objects and multiple inheritance

Color = {}
Color.__index = Color

function Color:new(r, g, b)
    local instance = setmetatable({}, self)
    instance.r = r or 0
    instance.g = g or 0
    instance.b = b or 0
    return instance
end

function Color:setColor(r, g, b)
    self.r = r
    self.g = g
    self.b = b
end

function Color:getColor()
    return self.r, self.g, self.b
end

function Color:getColorFormat()
    return "R:"..self.r.." G:"..self.g.." B:"..self.b
end

Multiple inheritance is also possible.

It's recommended to design our structure of classes in a way that we don't need multiple inheritance, but if we need it, we can use it.

We are adding a new class Color.

ColoredCircle = {}
ColoredCircle.__index = function(tbl, key)
    return tbl.Circle[key] or tbl.Color[key]
end

function ColoredCircle:new(x, y, radius, r, g, b)
    local instance = {
        Circle = Circle:new(x, y, radius),
        Color = Color:new(r, g, b)
    }
    setmetatable(instance, self)
    return instance
end

myColoredCircle = ColoredCircle:new(25,25,10, 255, 128, 64)

print(myColoredCircle:getPosition())     -- 25	25
print(myColoredCircle:getRadius())       -- 10
print(myColoredCircle:getArea())         -- 314.15926535898
print(myColoredCircle:getColorFormat())  -- R:255 G:128 B:64

We have the class ColoredCircle, that inherits from Circle and Color.

This script should have the classes Color and Circle (and Shape) in the same script to work. I'm not copying them to avoid repeating.

Now the __index, lines 4-6, doesn't have a table, but a function. This function returns the called function from Circle if it is there (or in Shape) or from Color.

This use of __index with a function is why multiple inheritance is not recommended. This function can't be optimized by the compiler and the process is slower than single inheritance.


Error handling

function calculateSquareRoot(number)
    return math.sqrt(number)
end

function safeSquareRoot(input)
    local success, result = pcall(calculateSquareRoot, tonumber(input))

    if success then
        print("The square root is:", result)
    else
        print("Error occurred:", result) 
    end
end

safeSquareRoot(25)       -- The square root is:	5.0
safeSquareRoot("hello")  -- Error occurred: main.lua:2: bad argument #1 to 'sqrt' (number expected, got nil)
safeSquareRoot(100)      -- The square root is:	10.0

|} We can catch errors, to avoid run-time errors, so our script can go on running.

In this example we are trying to calculate the square root of "hello", which will throw an error, since it can't be converted to a number.

The system function to intercept errors is "pcall", in line 8.

The first parameter of "pcall" is the name of the function that we are calling and the next parameters are the parameters of our function.

The first parameter returned is true (success) or false (error).

In case of success, the next parameters are the parameters returned by our function.

In case of error, the second parameter is the description of the error.


Libraries

system functions are grouped in libraries, and called as LibraryName.FunctionName, except the functions in the basic library that doesn't need a library name.

We have seen several basic functions, like: print, type, tostring, pairs, select, setmetatable,... Other libraries are:

- table: tables manipulation

- math: mathematical operations

- string: string manipulation

- os: date and time functions

- bit32: bitwise operations on integers. Standard Lua has bitwise operators, but not Luau. So probably we will use this library instead of operators.

Standard Lua has more libraries and can use externally developed ones. Luau, for security reasons, is restricted to its own libraries.

LuaSL will add the ll library with all the ll functions, like: ll.Say, ll.GetPos,..


Modules and packages

A module is a type of script that is not executed on its own, but will be included in another script.

Modules return a table that will used in the main script. This table can be anything: values and functions, an object, several objects...

Standard Lua also has packages, which have several modules compiled together, but Luau has modules only.


Debugging

It seems that we will not have debugging in the first LuaSL version, but it will be added later.

Luau has the possibility to add a debugger to set stop points, watch variables, step on code and inspect variables


Co-routines

They will be also added later, not in the first version.

It allows that a function can pause itself while waiting for something to happen, and another function can resume it when that happens.

It will be useful for functions that use asynchronous calls or timers, and other advanced interactions.