class, module, coroutine, begining error

+ some correction and addition.
This commit is contained in:
Jérémi N ‘EndMove’ 2023-01-16 00:47:06 +01:00
parent 655ce78eee
commit 74b02df3c1
Signed by: EndMove
GPG Key ID: 65C4A02E1F5371A4
3 changed files with 317 additions and 14 deletions

217
README.md
View File

@ -1,6 +1,7 @@
# cheat-sheet-lua
Here is the IO-Project cheat sheet to quickly learn the "Lua" programming language
Here is the IO-Project cheat sheet to quickly learn the "Lua" programming language.
I suggest you to consult the documentation of lua for more information on the language, it is available by following [this link](https://www.lua.org/manual/5.3/).
## Table of contents
@ -8,7 +9,7 @@ Use this table of contents to travel more easily through this cheat sheet.
- [cheat-sheet-lua](#cheat-sheet-lua)
- [Table of contents](#table-of-contents)
- [The basics](#the-basics)
- [Basics](#basics)
- [Code comments](#code-comments)
- [Variables and loop](#variables-and-loop)
- [Functions](#functions)
@ -16,8 +17,13 @@ Use this table of contents to travel more easily through this cheat sheet.
- [Tables, Array, dict..](#tables-array-dict)
- [Metatables and metamethods](#metatables-and-metamethods)
- [Class-like tables and inheritance.](#class-like-tables-and-inheritance)
- [Coroutine](#coroutine)
- [Error handling](#error-handling)
- [Modules](#modules)
## The basics
## Basics
> We'll now introduce the basics of lua, starting with comments, variables, loops and functions.
### Code comments
@ -163,14 +169,13 @@ print 'hello' -- Works fine.
## Advanced
> Let's move on to more advanced notions. With the notion of table, class, module, coroutine, meta-programming and module.
### Tables, Array, dict..
````lua
-- Tables = Lua's only compound data structure;
-- they are associative arrays.
-- Similar to php arrays or js objects, they are
-- hash-lookup dicts that can also be used as lists.
Tables are the only compound data structure in Lua, they are associative arrays. Similar to php arrays or js objects, they are hash-lookup dicts that can also be used as lists.
````lua
-- Using tables as dictionaries / maps:
-- Dict literals have string keys by default:
@ -218,11 +223,9 @@ end
#### Metatables and metamethods
````lua
-- A table can have a metatable that gives the table
-- operator-overloadish behavior. Later we'll see
-- how metatables support js-prototypey behavior.
A table can have a metatable that gives the table operator-overloadish behavior. Later we'll see how metatables support js-prototypey behavior.
````lua
f1 = {a = 1, b = 2} -- Represents the fraction a/b.
f2 = {a = 2, b = 3}
@ -283,3 +286,193 @@ eatenBy = myFavs.animal -- works! thanks, metatable
````
#### Class-like tables and inheritance.
Classes aren't built in, there are different ways to emulate them with tables and metatables.
The different ways to define a class in Lua are not easy to understand, so I suggest you to look at the [following document](support/class.lua) implementing 3 types of class definition. The last one being the one I chose (my preferred method).
````lua
-- Explanation for this example is below it.
Dog = {} -- 1.
function Dog:new() -- 2.
newObj = {sound = 'woof'} -- 3.
self.__index = self -- 4.
return setmetatable(newObj, self) -- 5.
end
function Dog:makeSound() -- 6.
print('I say ' .. self.sound)
end
mrDog = Dog:new() -- 7.
mrDog:makeSound() -- 'I say woof' -- 8.
-- 1. Dog acts like a class; it's really a table.
-- 2. function tablename:fn(...) is the same as
-- function tablename.fn(self, ...)
-- The : just adds a first arg called self.
-- Read 7 & 8 below for how self gets its value.
-- 3. newObj will be an instance of class Dog.
-- 4. self = the class being instantiated. Often
-- self = Dog, but inheritance can change it.
-- newObj gets self's functions when we set both
-- newObj's metatable and self's __index to self.
-- 5. Reminder: setmetatable returns its first arg.
-- 6. The : works as in 2, but this time we expect
-- self to be an instance instead of a class.
-- 7. Same as Dog.new(Dog), so self = Dog in new().
-- 8. Same as mrDog.makeSound(mrDog); self = mrDog.
----------------------------------------------------
-- Inheritance example:
LoudDog = Dog:new() -- 1.
function LoudDog:makeSound()
s = self.sound .. ' ' -- 2.
print(s .. s .. s)
end
seymour = LoudDog:new() -- 3.
seymour:makeSound() -- 'woof woof woof' -- 4.
-- 1. LoudDog gets Dog's methods and variables.
-- 2. self has a 'sound' key from new(), see 3.
-- 3. Same as LoudDog.new(LoudDog), and converted to
-- Dog.new(LoudDog) as LoudDog has no 'new' key,
-- but does have __index = Dog on its metatable.
-- Result: seymour's metatable is LoudDog, and
-- LoudDog.__index = LoudDog. So seymour.key will
-- = seymour.key, LoudDog.key, Dog.key, whichever
-- table is the first with the given key.
-- 4. The 'makeSound' key is found in LoudDog; this
-- is the same as LoudDog.makeSound(seymour).
-- If needed, a subclass's new() is like the base's:
function LoudDog:new()
newObj = {}
-- set up newObj
self.__index = self
return setmetatable(newObj, self)
end
````
### Coroutine
Let's turn now to coroutines. Coroutines are functions that can be suspended and resumed at a later time. They are used to implement iterators, generators and event loops and represent a line of execution with its own stack. In other words, they can be compared to threads.
````lua
-- Create a coroutine that prints 'Hello' and then stops.
coHi = coroutine.create(function () print('Hello') end)
print(coHi) -- thread: 0x7f9c0c00a0c0
-- Coroutine status can be 'suspended', 'running' or 'dead'.
-- The coroutine is created in the 'suspended' state.
-- Resume the coroutine. It will print 'Hello' and stop.
coroutine.resume(coHi) -- return 'true'
print(coroutine.status(coHi)) -- 'dead'
-- We can also pass arguments to the coroutine.
-- The arguments of the first resume are passed to the
-- function of the coroutine. The following arguments
-- are passed to the yield function.
routine = coroutine.create(function (a, b, c)
print('first print: ', a, b, c)
print('yield1: ', coroutine.yield())
print('yield2: ', coroutine.yield('a variable'))
return(a+b+c)
end)
-- will run the coroutine until the first yield.
coroutine.resume(routine, 1, 2, 3)
-- run the coroutine until the second yield passing
-- the arguments 4, 5 and 6 to the 1er yield and
-- retrieve the return value of the second yield.
print('out routine: ' , coroutine.resume(routine, 4, 5, 6))
-- this will run out the second yield and made the
-- adition of 'a+b+c' and kill the coroutine.
print(coroutine.resume(routine, 7, 8, 9)) -- 1+2+3 = '6'
-- All these steps will print:
--[[
first print: 1 2 3
yield1: 4 5 6
out routine: true a variable
yield2: 7 8 9
true 6
--]]
````
### Error handling
Lua allows low-level error handling with the `error` function and high-level error handling with the `assert` function. The `error` function raises an error and handles it with the `pcall` or `xpcall` function. The `assert` function checks a condition and raises an error if the condition is not met.
````lua
-- Throw an error if the first argument is false
-- the second argument is the error message.
assert(type(firstvariable) = 'string', 'not a string')
-- TODO to continue
````
### Modules
Modules are a way to organize your code. They are a way to group functions and variables together in a single file. You can then use the module in other files by using the `require` function.
````lua
-- Suppose the file mod.lua looks like this:
local M = {}
local function sayMyName()
print('Hrunkner')
end
function M.sayHello()
print('Why hello there')
sayMyName()
end
return M -- Return the table M.
-- Another file can use mod.lua's functionality:
local mod = require('mod') -- Run the file mod.lua.
-- require is the standard way to include modules.
-- require acts like: (if not cached; see below)
local mod = (function ()
<contents of mod.lua>
end)()
-- It's like mod.lua is a function body, so that
-- locals inside mod.lua are invisible outside it.
-- This works because mod here = M in mod.lua:
mod.sayHello() -- Says hello to Hrunkner.
-- This is wrong, sayMyName only exists in mod.lua:
mod.sayMyName() -- error
-- require's return values are cached so a file is
-- run at most once, even when require'd many times.
-- Suppose mod2.lua contains "print('Hi!')".
local a = require('mod2') -- Prints Hi!
local b = require('mod2') -- Doesn't print; a=b.
-- dofile is like require without caching:
dofile('mod2.lua') --> Hi!
dofile('mod2.lua') --> Hi! (runs it again)
-- loadfile loads a lua file but doesn't run it yet.
f = loadfile('mod2.lua') -- Call f() to run it.
-- loadstring is loadfile for strings.
g = loadstring('print(343)') -- Returns a function.
g() -- Prints out '343', nothing printed before now.
````

102
support/class.lua Normal file
View File

@ -0,0 +1,102 @@
-- ============================================================================
-- This is a simple Person class (Raw example without synthetic sugar).
-- ============================================================================
Person1 = {}
-- Constructor
function Person1.new(self, name, age)
local o = {}
self.__index = self
setmetatable(o, self)
o.name = name
o.age = age
return o
end
-- Methods
function Person1.getName(self)
return self.name
end
function Person1.getAge(self)
return self.age
end
-- Usage
local instance = Person1.new(Person1, "John", 30)
print('name: ' .. instance.getName(instance)) -- John
print('age: ' .. instance.getAge(instance)) -- 30
-- Garbage collection
Person1 = nil
instance = nil
-- ============================================================================
-- This is a simple Person class (Synthetic sugar example).
-- ============================================================================
Person2 = {}
-- Constructor
function Person2:new(name, age)
local o = {}
self.__index = self
setmetatable(o, self)
o.name = name
o.age = age
return o
end
-- Methods
function Person2:getName()
return self.name
end
function Person2:getAge()
return self.age
end
-- Usage
local instance = Person2:new("John Doe", 50)
print('name: ' .. instance:getName()) -- John Doe
print('age: ' .. instance:getAge()) -- 50
-- Garbage collection
Person2 = nil
instance = nil
-- ============================================================================
-- This is my class definition method (with Synthetic sugar example).
-- ============================================================================
Person = {}
-- Constructor
function Person:new(name, age)
local this = setmetatable({}, {__index = self})
this.name = name or 'EndMove'
this.age = age or 20
return this
end
-- Methods
function Person:getFName()
return 'name: ' .. self.name
end
function Person:getFAge()
return 'age: ' .. self.age
end
-- Usage
local instance = Person:new("Gashy", 21)
print(instance:getFName()) -- name: Gashy
print(instance:getFAge()) -- age: 21
-- Garbage collection
Person = nil
instance = nil
-- ============================================================================
-- Thanks for reading!

View File

@ -1,3 +1,8 @@
-- ============================================================================
-- Let's study the different loops offered by the Lua language.
-- ============================================================================
-- Jeb while loop
local jebSum = 0
print('jeb : '..jebSum)
@ -39,3 +44,6 @@ while true do
if true then break end
end
print('Breaking out -> Done')
-- ============================================================================
-- Thanks for reading!