By logical operations I mean “and”, “or”, and “not”
My use case is that for my custom Signal module I would like to be able to do things such as:
local s1 = Signal.New()
local s2 = Signal.New()
(s1 and s2):Connect(function()
-- fires after both s1 AND s2 are fired
end)
(s1 or s2):Connect(function()
-- fires after either s1 OR s2 is fired
end)
Alternatively I think the most correct way to do this would be:
local s1 = Signal.New()
local s2 = Signal.New()
(s1*s2):Bind(function()
-- fires after both s1 AND s2 are fired
end)
(s1+s2):Bind(function()
-- fires after either s1 OR s2 is fired
end)
A lot of this doesn’t really make sense to practically use. s1+s2 would invoke the __add metamethod and (s1 and s2) would just return s2 because of how ternary operators work. Unfortunately there’s not much you can do with variadic variables other than calling with them as the arguments and assigning them.
--Assignment to variables / returning multiple variables from a function
local part,position,normal,material = workspace:FindPartOnRayWithIgnoreList()
--Used as arguments in a function
function printEverything(...)
local t = {...}
for i = 1,#t do
print(t[i])
end
end
printEverything(1,2,3,4,5,6,"a","b","c")
If you want something to happen because of two conditions then you’re better off polling. Here’s an example of polling that could achieve the same result.
local var1 = false
local var2 = false
spawn(function()
local start = tick()
repeat
wait()
until var1 and var2
var1 = false
var2 = false
--Your code
print("I waited",tick()-start,"seconds for this to print!")
end)
--debug code given as an example
wait(10)
var1 = true
wait(1)
var2 = true
-->>> I waited 10.936549663544 seconds for this to print!
Please note that this is rudimentary code and the inaccuracy is due to the massive yield (wait()).
You can already achieve the (s1*s2) with not that much more code than what you already wrote.
local Signal1 = Signal.new()
local Signal2 = Signal.new()
local function functionToConnectTo()
end
Signal1:Connect(functionToConnectTo)
Signal2:Connect(functionToConnectTo)
Essentially you connect both of the events to the same function. This doesn’t take up twice the memory merely because you’re connecting both events to one variable which references one function.
I’m asking for a feature to overload this just how you can overload addition
I don’t really understand how this relates to what I’m requesting
Yea you’re right about :Bind (same as Roblox’s :Connect) but if instead it’s :Wait() then its a little more complicated
I think you misunderstand what I’m asking, I’m not asking for Roblox to implement this into their BindableEvent class, I will be implementing this with multiplication and addition into my own Signal class but I believe it would be cleaner if it were using the logical operations instead
Essentially you’re wanting to perform some sort of variadic equivalent but through that or gate. You don’t have to comment on it if it seems meaningless to you.
I do know what you’re talking about. I don’t really see a use case for it though, as there are already ways to do this. If you can provide some use cases that don’t include syntax candy, I would definitely like to know!
I still don’t understand how this is variadic because it’s only two parameters
Also it wouldn’t go through an or gate it would overload that and just call the function instead
Can you provide a use case of when metamethods aren’t syntax candy?
The fact that and, or, and not work the way they do is a great feature. They’re predictable and have no side effects. I would really dislike it if the logical operators could be overloaded because that makes it harder to write some things.
For example, it’s common to have code like this
local value = condition and a or b
If and and or were unpredictable and could have side effects, we would instead have to write
local value
if condition then
value = a
else
value = b
end
This gets even worse if not can be overloaded. Then we can no longer write code like this:
if not condition then
-- do things
end
Instead we have to write
if condition then
else
-- do things
end
since not won’t necessarily be consistent anymore and we want to avoid side-effects.
Somewhat-similar arguments can be made for other operators, but the other operators are not used in such fundamental ways. The other operators, even before metamethods, had different results based on what type you used them on. The logical operators have the consistent results for every type (except bool) and are used in a type-agnostic way. Changing this would make writing new code harder (as shown above) and could break existing code.
If you want to get something similar to overloading and, or, and not, then just overload __mul, __add, and __unm which corresponds to a * b, a + b, and -a
But overloading is optional and you can consciously choose what to overload so this would not break old code and for new code you are making a conscious decision about it, furthermore if they are only overloaded when both parameters are tables with the same metatable (similar to __eq) then your ternary statements would still work
As for creating public modules you wouldn’t abuse this in a way that would make it confusing which I assume is the same principle that needs to be followed with any other metamethod - or part of lua
Or something along those lines would be much more clear to me (I wouldn’t need to enter your Signal.lua to find out what s1+s2 and s1*s2 mean) and accomplishes the same thing.
Idk I think you would still need to know what it does (I would for clarification at the very least)
Even if you don’t, you still need to enter the module for getting the function name since intellisense doesn’t work on my modules because of their organization
So a 2 word comment on the operator wouldn’t add much extra and imo it looks much cleaner
Overloading is not possible. There is no metamethod to invoke; internally, or and and statements compile to their equivalent if x and if not x long representations.
There aren’t “gates” really. A TEST or TESTSET instruction is used to compare the truthiness of the values, followed by a JMP to outside.
A x or y might look like…
GETGLOBAL
TEST
JMP
GETGLOBAL
Where it first loads the x global into the register and tests whether it evaluates to true or not. If it’s true, the TEST will do nothing, and the JMP will be hit to skip over the GETGLOBAL, otherwise the TEST skips over the JMP and then runs the GETGLOBAL, loading y into the register instead.
There used to he a pdf called No-Frills or something like that with a lot of information on the internals but the luaforge page for it went down some time ago.
Also if the metamethods were to be made, would it still be bad because it would slow down everything else since everytime a logical operation were made it would have to check if the metamethod is active?
Lua DOES have a table->flags optimization used for optimizing heavy usage of metamethods, so the speed difference if the metamethod wasn’t present wouldn’t be grave, but it’d still not work well because it’d mean that both if statements and the or/and keywords would be affected, since they both work the same way internally.