I am cleaning up another person's code, and I really want to be sure of this before I make a large number of replacements. The LUA documentation states that a Boolean evaluation will see anything other than false or nil, as true. Is this true of more complex objects such as classes and tables?
There is a class Monitor, which takes in a function and acts based on the boolean return of that function. It is called like this:
Monitor(middleFunction,otherparams):hook("doThing",otherstuff)
The function middleFunction has this:
function middleFunction(monitor,arg)
return otherFunction() ~= nil
My understanding is that, since middleFunction is returning a boolean based on whether otherFunction is not returning nil, I could cut out the entire class and just pass otherFunction to Monitor. If the function returns nil, it will evaluate as false, and if it returns anything else it will evaluate as true:
Monitor(otherFunction,otherparams):hook("doThing",otherstuff)
Is this a safe change? In some cases I have no visibility into either otherFunction or Monitor, but I know that otherFunction returns either a table or nil. Are there any possible cases where it might not evaluate properly if I make this change?
It's unsafe, the boolean evaluation only works for a single expression,
function Monitor(f, p)
if f(monitor, arg) then
end
end
But it doesn't work for relational operators, this example only accepts the boolean value true
function Monitor(f, p)
if f(monitor, arg) == true then
end
end
In Lua, the boolean evaluation of a value is based on whether it is considered "truthy" or "falsy". In general, the following values are considered falsy:
false
nil
All other values, including complex objects such as classes and tables, are considered truthy. This means that any table or class that exists and is not nil will evaluate to true in a boolean context, even if it is empty or has no properties.
When checking the truthiness of a table, it is best to check if the table is not nil and then check if the table is empty or not.
Related
I wanted to write the simplest possible function which let me return the desired value in a nameless table and, ideally, it should be something like this:
function RL_MyTool:Version(n)
return {"0.4.0", "20221003-0230", "13.5.5"}[n]
end
But, of course, that's not allowed in Lua...
So, off the top of my head, I can think on these two other possibilities:
1:
function RL_MyTool:Version(n)
local t = {"20221003-0230", "13.5.5"}
return t[n] or "0.4.0"
end
2:
function RL_MyTool:Version(n)
local n, t = n or 1, {"0.4.0", "20221003-0230", "13.5.5"}
return t[n]
end
Both of them slightly different from each other but doing the same, counting with the advantage of returning a default value if no argument is given, which is good. BUT... Do you think I could still have a possibility of writing it like in the very simplest fashion way above? Basically, what I'd like is not even have to use a single variable or table declaration along the function but still let me return the specified table entry when called.
Well, that's all. Of course if it's finally not possible (as I'm afraid) it won't be the end of the world 🙄, but I wanted to be sure I wasn't missing any Lua trick or something that let me do it more like I firstly imagined... Thanks!
P.S. Oh, I don't see how, but of course if it could be achieved without the necessity of even using a table at all, that would be equally valid or even better.
EDIT: BTW, for the record and based in #Piglet (great!) answer, I got to reduce it even more this way:
function RL_MyTool:Version(n)
return ({"0.4.0", "20221003-0230", "13.5.5"})[n or 1]
end
Improving code usability/maintenance a bit at the same time by avoiding duplicated values... Kind of a win-win-win 😁
Just put the table in parenthesis.
function RL_MyTool:Version(n)
return ({"0.4.0", "20221003-0230", "13.5.5"})[n] or "0.4.0"
end
But what is the purpose of this? Code should be easy to read and easy to work on. There is absolutely no reason to not use a local table. You don't have to pay a dollar for each line of code.
Is there any way that I can get the true value of an OR operation? Something like this?
=OR(value1, value2, value3) return value that is true
try:
=OR(value1, value2, value3)=TRUE
example:
=OR(A1=1, A1=2, A1=3)=TRUE
Taking this question's title literally, the value of any true Or function is always True. However that's probably not what OP is seeking but there's a fundamental misunderstanding that an Or function can have values. Specifically, this question makes a nonsensical assumption that an OR function can have value1, value2, value3. An Or function contains evaluations that return true or false -- no third value possible.
To illustrate, what value would be returned from this Or formula?
=Or(Not(Isnumber(A1)),len(A1)<5,left(C1,1)="G")
However, I understand that this is probably specific to some customized situation. The solution is that some other formula, functionality is needed. If you're evaluating a single cell (i.e. if cell A1 has any three values), then Erik Tyler's proposal of just using an if statement is your answer
=ArrayFormula(IF(OR(A1={5,10,15}),A1,))
(a less elegant but simplified formula that returns the same would be: =if(Or(A1=5,A1=10,A1=15),A1,)
For finding some true values in a range, there are all kinds of possibilities. However to get you started, you might consider using a filter function combined with boolean logic of (evaluation1)+(evaluation2).
See below formula will list off cell addresses of all true values in this Filter function.
=FILTER(Address(ROW(A:A),COLUMN(A:A),4),(A:A=3)+(A:A=5)+(A:A="Hello"))
MATCH (c:OBJ {dummy:false})
where [{param} is null or [(c)-[]->(p:PRO {dummy:false}) WHERE p.val ={param} | true ] ]
return c
I have a big query from which there is this simple part. But
[{param} is null or [(c)-[]->(p:PRO {dummy:false}) WHERE p.val = {param} | true] ]
part is always returning true even if p.val ={param} is false. What did I do wrong here? The syntax looks fine for me.
A pattern comprehension will always return a list, even if it is empty.
So, the following will never equate to false or NULL:
[(c)-[]->(p:PRO {dummy:false}) WHERE p.val = {param} | true]
This query (which tests the size of the inner comprehension result) will probably work for you:
MATCH (c:OBJ {dummy:false})
WHERE [$param IS NULL or SIZE([(c)-->(p:PRO {dummy:false}) WHERE p.val = $param | true]) > 0 ]
RETURN c
There's a couple things going on here. Note cybersam's answer, as it relates to the pattern comprehension within.
However, the bigger problem is that the WHERE clause will ultimately be evaluating a list, NOT a boolean!
By using square brackets for the entirety of your WHERE clause, that means you're creating a list, and its contents will be whatever is inside. The stuff inside will evaluate to a boolean, so this means that there are two possibilities for how this will turn out:
WHERE [true]
or
WHERE [false]
and in either of these cases, these are NOT booleans, but single-element lists, where the only element in the list is a boolean!
Using WHERE on a list like this will ALWAYS evaluate to true. No matter what is in the list. No matter how many elements are in the list. No matter if the list is empty. If the list itself exists, it's going to be evaluated as true, and the WHERE clause succeeds.
So to fix all this, do NOT use square brackets as some means to compartmentalize boolean logic. Use parenthesis instead, and only if you really need them:
MATCH (c:OBJ {dummy:false})
WHERE ( {param} is null or (c)-->(:PRO {dummy:false, val:{param}}) )
RETURN c
In the above, the parenthesis in use when using the WHERE clause aren't really needed, but you can use them if you like.
This should also be a better way of expressing the predicate you want. In this case we don't need the pattern comprehension at all. It's enough to say that we either need the {param} parameter to be null, or this pattern (where one of the properties is the {param} parameter) must exist.
If you really do end up needing a pattern comprehension, follow cybersam's advice and make sure you're testing whether the the list resulting from the comprehension is empty or non-empty.
Rawset function in lua generally is passed table, index and value but I came across this code:
rawset(tbl,name,{})
and
rawset(tbl,name, function() end)
Rawset function returns a table, so what does it mean to have a table or function in rawset function in place for value ?
Lua tables can hold values of all types, including tables and functions, and they can be heterogeneous: not all values need to be of the same type.
See http://www.lua.org/manual/5.2/manual.html#2.1.
From reference manual:
rawset (table, index, value): Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil, and value any Lua value.
What this means:
table's metatable is not used: that's why it is "raw" set, the field is added directly; without raw, the table's metatable will be used to handle the "set" action;
index any value different from nil: in Lua, this really means any type of Lua object other than nil: a number, a function, another table, etc (Lua ref manual lists all types);
value any Lua value: same as previous, but can even be nil: if set to nil, effectively removes item from table.
So index being name just indicates the table is an associative array (unless name is a number but that would be misleading), in first case the associated value is another table, in the second case it is a Lua function.
Is there a method for checking if a table contains a value ? I have my own (naive) function, but I was wondering if something "official" exists for that ? Or something more efficient...
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
By the way, the main reason I'm using this functions is to use tables as sets, ie with no duplicate elements. Is there something else I could use ?
You can put the values as the table's keys. For example:
function addToSet(set, key)
set[key] = true
end
function removeFromSet(set, key)
set[key] = nil
end
function setContains(set, key)
return set[key] ~= nil
end
There's a more fully-featured example here.
Given your representation, your function is as efficient as can be done. Of course, as noted by others (and as practiced in languages older than Lua), the solution to your real problem is to change representation. When you have tables and you want sets, you turn tables into sets by using the set element as the key and true as the value. +1 to interjay.
I know this is an old post, but I wanted to add something for posterity.
The simple way of handling the issue that you have is to make another table, of value to key.
ie. you have 2 tables that have the same value, one pointing one direction, one pointing the other.
function addValue(key, value)
if (value == nil) then
removeKey(key)
return
end
_primaryTable[key] = value
_secodaryTable[value] = key
end
function removeKey(key)
local value = _primaryTable[key]
if (value == nil) then
return
end
_primaryTable[key] = nil
_secondaryTable[value] = nil
end
function getValue(key)
return _primaryTable[key]
end
function containsValue(value)
return _secondaryTable[value] ~= nil
end
You can then query the new table to see if it has the key 'element'. This prevents the need to iterate through every value of the other table.
If it turns out that you can't actually use the 'element' as a key, because it's not a string for example, then add a checksum or tostring on it for example, and then use that as the key.
Why do you want to do this? If your tables are very large, the amount of time to iterate through every element will be significant, preventing you from doing it very often. The additional memory overhead will be relatively small, as it will be storing 2 pointers to the same object, rather than 2 copies of the same object.
If your tables are very small, then it will matter much less, infact it may even be faster to iterate than to have another map lookup.
The wording of the question however strongly suggests that you have a large number of items to deal with.
I can't think of another way to compare values, but if you use the element of the set as the key, you can set the value to anything other than nil. Then you get fast lookups without having to search the entire table.
-- in some helper module
function utils_Set(list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
-- your table here
long_table = { "v1", "v2", "v1000"}
-- Consult some value
_set = utils_Set(long_table)
if _set["v1"] then print("yes!") end