How to use a value in a table inside itself (Lua language)? - lua

I have a lua table like this:
local defaultSize = 14
local field = {
sizeA = defaultSize,
sizeB = sizeA,
}
My intention is to set sizeB to the value of field.sizeA, however the code above does not work. field.sizeB is nil in this case.
How to set sizeB to whatever sizeA is inside the table definition directly?

You could have an init function in table and call that:
local defaultSize = 14
local field = {
init = function (self, size)
self.sizeA = size or defaultSize -- size only if given, otherwise defaultSize
self.sizeB = self.sizeA
end
}
field:init() -- implicit "self" arg is "field", defaultSize will be used
field:init(16) -- size will be 16 rather than 14
print(field.sizeB) -- prints 14
This has the clear advantage of aggregating all initialization of table instance in one place, you can have conditionals etc once your logic gets more complex. You don't have to have init() as member of table, but it is always a good idea to keep dependencies obvious and close together.

Related

What does it mean if a mutating function setting it's self equals to another function

I was going through Apple's Arkit project sample. I was trying to understand the code since, I am still learning. I saw a function setting it self equals to another function can someone please explain what these functions are exactly doing. Please brief in detail.In the code the "mutating func normalize()" is setting it self to self.normalized why is it. What this code is doing. Can we not simply call "func normalized()" seems like we are re-creating the same function.
mutating func normalize() {
self = self.normalized()
}
func normalized() -> SCNVector3 {
if self.length() == 0 {
return self
}
return self / self.length()
}
func length() -> CGFloat {
return sqrt(self.x * self.x + self.y * self.y)
}
Values types in Swift can be mutable and immutable . So when you create struct( or any other value type) and assign it to variable (var) it is mutable and you call normalize() on it. It means that struct won’t be copied to another peace of memory and will be updated in place (will act like reference type). But when you assign it to constant (let) - it can’t be mutated so the only way to update values in this struct is to create new one with updated values as with normalized() method. Regarding your question - normalize() is just reusing logic for normalizing vector from normalized(). So this is completely fine solution. Assigning to self is only permitted in mutable methods. It’s basically rewrites value of struct with new one.
I'm assuming that this fragment is in a struct rather than a class.
self.normalized() makes a copy of self and divides the copy's components by its length and then returns the copy. self is not affected.
self.normalize() gets a normalised version of self and then replaces self by the copy. So it changes in place.
Under the hood, every member function passes self as an implicit argument. i.e. to the compiler the declaration looks like this:
func normalised(self: SCNVector3) -> SCNVector3
Putting mutating on the front of a function definition makes the hidden argument inout
func normalise(self: inout SCNVector3)
So, if you have
var a = SCNVector3(3, 4, 0)
let b = SCNVector3(4, 3, 0)
let c = b.normalized()
a.normalize()
After that code, c would be (0.8, 0.6, 0) and a would be (0.6, 0.8, 0). b would be unchanged.
Note that a has to be declared with var because it is changed in place by normalise()
Edit
In the comments khan asks:
What i am not able to understand is why do we have to create a func again we can use "func normalized"
The point being made is why can't we do something like this:
var a = SCNVector3(3, 4, 0)
a = a.normalized()
and not have the normalise() function at all?
The above will have exactly the same effect as a.normalize() and, in my opinion[1], is better style, being more "functional".
I think a.normalize() exists only because it is common in Swift to provide both forms of the function. For example, with sets you have both union() and formUnion(): the first returns the union of one set with another, the second replaces a set with the union of itself and another set. In some cases, the in place version of the function may be more efficient, but not, I think, with this normalize function.
Which you choose to use is a matter of your preference.
[1] Actually, the better style is
let a = SCNVector3(3, 4, 0).normalized()

Love 2D(Lua) unexpected nil in object

Trying to get my feet wet with LUA and Love2D, and I am having an issue with object instantiation / access in Lua.
Source with the bug can be found here: https://bitbucket.org/dannsee/love_scrollingshooter
I am In my main, I create an object, Enemies
enemies = Enemies:new()
and inside of the enemies object, i create an object to hold peristant values, which I am calling Timers.
timers = Timers:new()
So the enemies 'constructor' method looks (basically) like this
Enemies = {} -- so that Enemies will not be nil when new() is called
timers = {} -- so that timers will be accessible in the class scope
function Enemies:new(enemies)
enemies = enemies or {}
timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
while the Timers being created are looking as such
Timers = {} -- so that Timers will not be nil when new() is called
function Timers:new(timers)
timers = timers or {
miniBombTimerMax = 0.2,
miniBombTimer = minibombTimerMax
}
setmetatable(timers, self)
self.__index = self
return timers
end
But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.
timers.miniBombTimer -- Produces nil exception
It seems to me that this should both 1. be in scope, since it is an object created inside this class, and is instantiated locally as timers = {} before it is assigned a value, and 2. not nil becuase it is being given a value in the 'constructor'. But it seems there is more going on here that I am not grasping.
I am new to Lua, which may be obvious at this point, but from what I have read about variable scope it seems that this should be valid. I don't understand why the timers are not being created with values.
Careful with your globals! In Lua, it's very easy to accidentally set a global variable when you don't mean to, and it looks like that's exactly what's happening.
function Enemies:new(enemies)
enemies = enemies or {}
timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
On the third line here, since timers doesn't exist as a local variable here, this value ends up getting put into a global variable called timers instead. If you want to set a property of enemies, you need to mention enemies explicitly:
function Enemies:new(enemies)
enemies = enemies or {}
enemies.timers = Timers:new()
setmetatable(enemies, self)
self.__index = self
return enemies
end
Now, you write:
But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.
Lua doesn't really have any concept of being "inside an object" or "inside a class". In some languages, when you're writing code inside of a class, all of the class's members are in scope and you can refer to them "bare". Lua is not one of those languages; in Lua, if you want to refer to a "class member", you need to use the dot notation, explicitly stating which object you're accessing. (Or you can do the "advanced method", using _ENV.)
By the way...
timers = {} -- so that timers will be accessible in the class scope
From what I see in the question, this line doesn't do much; it just creates a global variable which is never used.
Also, this line in Enemies:new:
self.__index = self
This just sets Enemies.__index every time Enemies:new is called. This is fine, but you may as well just set it once:
function Enemies:new(enemies)
enemies = enemies or {}
enemies.timers = Timers:new()
setmetatable(enemies, self)
return enemies
end
Enemies.__index = Enemies

In Swift, how do I set every element inside an array to nil?

var roomsLiveStates = [Firebase?]()
for ref in roomsLiveStates {
if ref != nil {
ref = nil
}
}
}
This doesn't seem to work.
You can just set each to nil:
for index in 0 ..< roomsLiveStates.count {
roomsLiveStates[index] = nil
}
As The Swift Programming Language says in its Control Flow discussion of for syntax:
This example prints the first few entries in the five-times-table:
for index in 1...5 {
println("\(index) times 5 is \(index * 5)")
}
... In the example above, index is a constant whose value is automatically set at the start of each iteration of the loop. As such, it does not have to be declared before it is used. It is implicitly declared simply by its inclusion in the loop declaration, without the need for a let declaration keyword.
As this says, the index is a constant. As such, you can not change its value.
You can also use a map:
roomsLiveStates = roomsLiveStates.map { _ in nil }
This is less code and a good habit to get into for other cases where you may want to create a processed copy of an array without mutating the original.
if you want to set each element in array to a numberic value(int, float, double ...), you can try vDSP framework.
Please check this:
https://developer.apple.com/documentation/accelerate/vdsp/vector_clear_and_fill_functions
You can also just reassign the whole array to one that only contains nil like:
roomsLiveStates = [Firebase?](count: roomsLiveStates.count, repeatedValue: nil)
Although now that I think about it, this doesn't seem so good, because (probably?) new memory gets allocated which is not fast at all
EDIT: I just checked and found that using .map is a lot slower in Debug builds. However on Release builds, .map is about 20% faster. So I suggest using the .map version (which also is quiet a bit prettier ;)):
array = array.map { _ in nil }
Iterating the array to map it, will result in poor performance (iteration + new allocation).
Allocating the array all over (init(repeating...) is better, but still allocates a new array, very costly.
The best way would be to zero out the data without allocating it again, and as every C programmer knows, that's why we have bzero and memset for.
It won't matter much for small arrays in a non repeating action, and as long as you remember it - using the smallest code possible could make sense, so sometimes using map or init makes sense.
Final note on the test - map and init use multiple allocations of the same size in this test, which makes allocation allot faster than in real world usage.
In general, memory allocation is not your friend, it is a time consuming process that may result in having to defragment the heap, calling kernel code to allocate new virtual memory, and also must use locks and/or memory barriers.
import Foundation
guard CommandLine.argc == 2, let size = Int(CommandLine.arguments[1]),size > 0 else {
fatalError("Usage: \(CommandLine.arguments[0]) {size}\nWhere size > 0")
}
var vector = [Int].init(repeating: 2, count: size)
let ITERATIONS = 1000
var start:Date
var end:Date
start = Date()
for _ in 0..<ITERATIONS {
vector = vector.map({ _ in return 0 })
}
end = Date()
print("Map test: \(end.timeIntervalSince(start)) seconds")
start = Date()
for _ in 0..<ITERATIONS {
vector = [Int].init(repeating: 0, count: size)
}
end = Date()
print("init(repeating:,count:) test: \(end.timeIntervalSince(start)) seconds")
start = Date()
for _ in 0..<ITERATIONS {
let size = MemoryLayout.size(ofValue: vector[0]) * vector.count // could optimize by moving out the loop, but that would miss the purpose
vector.withUnsafeMutableBytes { ptr in
let ptr = ptr.baseAddress
bzero(ptr, size)
}
}
end = Date()
print("bzero test: \(end.timeIntervalSince(start)) seconds")
Results when running with an array of 5,000,000 items size (M1 Mac), compiled with optimizations:
Map test: 5.986680030822754 seconds
init(repeating:,count:) test: 2.291425108909607 seconds
bzero test: 0.6462910175323486 seconds
Edit:
Just realized it's also to initialize the memory using the initializeMemory(...) method.
Something like:
_ = vector.withUnsafeMutableBytes { ptr in
ptr.initializeMemory(as: Int.self, repeating: 0)
}
The performance is virtually the same as with bzero, and it is pure swift and shorter.

Swift Bug or Coding Error? For Loops in Structs

So I am trying to make an iOS app that checks prime numbers in an input field as practice. I refactored my code to have a struct specifically for calculation functions like isPrime. For some reason my for loops is not working correctly when its in the struct. It works if I refactored it back into the controller.
func isPrime(number:Int) -> Bool{
let start = 2
for var i = number-1; i > 1; i-- {
if (number % i == 0){
return true
}
}
return false
}
The debugger thingy gives back these inputs:
Types 12 into text field
number = 12
i = 14070095816392014214
Why is my variable i in the for loops so damn large? I also tested putting a stray variable inside the function and it does the same thing (ex; start_int = 14214124123232423)?
Did you try printing the value of your number variable inside the function?
Your logic seems to be reversed. if a number x is divisible by another number less than x, then x is not prime. You have returned true if x is divisible. it should be false.

How do I fix my string issue?

local background = display.newImage("black.png", 0, 0)
local submit = display.newImage("submit.png")
submit.x = display.contentWidth/2
submit.y = display.contentHeight-100
local nameInstructions = display.newText("Enter your name", 10, 50, native.systemFont, 24)
local usersName = native.newTextField(10, 100, 350, 50)
usersName.inputType = "default"
local function keyboardListener (event)
native.setKeyboardFocus(nil)
end
background:addEventListener("tap", keyboardListener)
local function reverseName(event)
reverseUsersName = string.reverse(usersName)
end
submit:addEventListener("tap", reverseName)
local reverse = display.newText(reverseUsersName)
reverse.x = display.contentWidth/2
reverse.y = display.contentHeight/2
Every time that I run this using my Corona SDK thing, I get this:
Bad argument #-1 to 'newText' (string expected, got nil)
stack traceback:
[C]: ?
[C]: in function 'newText'
...Corona Projects/Assignment 4.3/main.lua/src/main.lua:24: in main chunk
reverseName is in the local function reverseName(event), but this function is called once u press or tap on the submit . But here local reverse = display.newText(reverseUsersName), is called before you tap on the sumbit . That is why its giving you error.
The only place that reverseUsersName, accessed on line 24, is set, is inside the function reverseName(event). In this function, reverseUsersName is a global so after the function is run once, that variable will be accessible from other parts of your script, but until then, it does not exist.
Now in line 22 you've registered reverseName as event listener for "tap" events, but events are only generated after your script has been executed once (and in between calls to your script callbacks like reverseName and keyboardListener are callbacks), so when you create the display text just after, the variable does not yet exist.
So what you would have to do is update the text of the reverse display item in your reverseName listener so that every time you click on the button, the reversed name becomes visible. And because of that, you would have to declare your reverse variable above reverseName function so that it is available as an upvalue (read the Corona getting started docs, they are excellent and discuss this subtlety) in that function. And presumably you would want to initialize with showing the usersName rather than reverse.
So you would need something like
local reverse = display.newText(usersName)
local function reverseName(event)
reverseUsersName = string.reverse(usersName)
reverse.SetText(reverseUserName)
end
submit:addEventListener("tap", reverseName)
Note that if you want the string being displayed to be reversed every time you press tap, rather than only first time you press it, you will have to use
local function reverseName(event)
reverseUsersName = string.reverse(reverseUsersName)
reverse.SetText(reverseUserName)
end
reverseUsersName = usersName
Check your function reverseName and the text object(reverse) with the following code:
local reverse --[[ Initialize the object with a global scope,
so you can access it anywhere from the page. --]]
local function reverseName(event)
--[[ In the below line, usersName is a table value. It is the reason
of the error. For getting the string from the text field, you
have to provide 'usersName.text' --]]
reverseUsersName = string.reverse(usersName.text)
reverse.text = reverseUsersName -- Assign the text field value to your text object
end
submit:addEventListener("tap", reverseName)
reverse = display.newText("",20,20,nil,20) --see the parameters of display.newText()*
reverse.x = display.contentWidth/2
reverse.y = display.contentHeight/2
*Corona API: display.newText()

Resources