Be careful when using assert() and Why

That’s why I stated that.

However, my statements aren’t flawed and my example from before clearly demonstrates what I mean. Let’s say the cost of each evaluation was 500. You have 2 evaluations but since it’s an or statement, there is a chance you only have to do one evaluation. Hence, a chance of half a speed up(theoretically). Since computers work insanely fast, you won’t notice unless you are doing something very costly. However, that doesn’t mean what I stated is false information.

I don’t get why your talking about bytecode. The bytecode would still be the same. It’s a runtime optimization.

Good to know. I read this when I was planning to use it … Interesting and informative!

This is really good to know I frequently use assert() and was unaware of this.

It’s completely fine to use assert, however string formatting the error message may be slower since formatting a string includes checking the string types and goes through another work.

1 Like

Why does roblox dev forum say someone mentioned me here? there’s no mention here

Sorry for the mention, I tagged you for the image credit.

Sorry to bump, but for this example, is it necessary to do == true?
Or can I simply write return v or error(errorMessage)?

Thanks in advance.

I have also benchmarked this and these are my results

local function Assert(value)
	assert(type(value) == "number", "Bad Argument" .. value)
end

local function If(value)
	if type(value) ~= "number" then error("Bad Argument" .. value) end
end

local amount = 1000

local assertTotal = 0
for i = 1, amount do
	local t = os.clock()
	local a, b = 1, true
	for i = 1, 1000 do
		pcall(Assert, a)
		a, b = b, a
	end
	assertTotal += os.clock() - t
end
assertTotal /= amount

task.wait()

local ifTotal = 0
for i = 1, amount do
	local t = os.clock()
	local a, b = 1, true
	for i = 1, 1000 do
		pcall(If, a)
		a, b = b, a
	end
	ifTotal += os.clock() - t
end
ifTotal /= amount

print("Assert:", string.format("%.9f", assertTotal))
print("If    ", string.format("%.9f", ifTotal))

Results:

-- Assert:
0.004660541
0.004596083
0.005090250
0.004749107
0.004602356
0.004767745
0.004852163

-- If
0.004702491
0.004715973
0.004451382
0.004726072
0.004471088
0.004481933
0.004517734

so I would say if is around 0.0002 seconds faster

but if I change the a and b values to always be numbers and change the error message to
"Bad Argument" .. value .. string.format("%.3f", value)

then I get results

-- Assert:
0.000970206
0.001223040

-- If
0.000116331
0.000109242

now we can see that if is around 0.0009 seconds faster

so we should not blame assert for this but blame the string functions because this performance impact will effect any function if your passing string that has had any work done to it not only assert

so the best way to use assert is to pass a simple string into it like this

assert(type(value) == "number", "Bad Argument")

and now the performance should be very close to if

1 Like

okay, i am a little confused here, shouldnt it be
assert(type(number) =~ “number” ?

assert checks if the first parameter is true (or a non-nil value that isn’t false) and errors if it isn’t. In this case, we want to be sure the type is number.

Let’s take the example of:

fasterAssert(num == 123 or "Wrong number!")

When num is equal to 123, it results in true. This causes the or operator to short circuit and skip "Wrong number!" and instead pass true into fasterAssert.

But what if num is not equal to 123? Well in that case or looks at its second argument "Wrong number!" and because it is truthy (close enough to true), it accepts it and passes it into fasterAssert.

So there are two possibilities:

  1. true
  2. string which is truthy.

When something is truthy, it means that the if-statement will see it as true and evaluate its contents, but when comparing with == true, it will result in false as it isn’t exactly true. In both of these cases, the argument is always truthy. So in the fasterAssert function, the or operator will see "Wrong number!" as truthy, and return that instead always. It will in fact never error either.

Understanding JavaScript Truthy and Falsy - Stack Overflow

1 Like

Just use warn() so the code doesn’t stop. Error stops the code.

I made a warning version of assert(), so the code doesn’t stop and read what @bloodbonniekingnoob1 said below :point_down:

local function warn_assert(assertion:any, err:string)
   if typeof(assertion) == "boolean" then
      if assertion == false then
         warn(err)
      end
   else
      if assertion == nil then
         warn(err)
      end
   end
end

CC: @bloodbonniekingnoob1

The whole point of erroring is to stop the code from continuing in a broken state. If a function expected a number but got a boolean, then you’re going to want it to stop and tell you that before it tries to evaluate with it.

Warning is more for informing the user of a possible misuse that isn’t severe enough to cause issues, i.e. a Disable method that warns when the object is already disabled but continues because it won’t do anything.

1 Like

This is interesting. Although I have been getting nearer to 90% improvements with more calculations.
image

was this a dumb joke over me not understanding smth or did my brain die

Maybe team behind Luau can work on optimizing assert? I hope they do it at some point.

The problem doesn’t lie with assert.

The problem is that the string.format is slow which is also calculated even though it’s not needed