[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: assert with formatting
- From: Hisham <h@...>
- Date: Fri, 13 Jul 2018 18:06:03 -0300
On 13 July 2018 at 17:17, Sean Conner <sean@conman.org> wrote:
> It was thus said that the Great Hisham once stated:
>> On 13 July 2018 at 11:23, Pierre Chapuis <catwell@archlinux.us> wrote:
>> >> Um, but wouldn't
>> >>
>> >> format_assert(a == 1 , "'a' should be '%d', but was '%s'",1,tostring(a))
>> >>
>> >> *also* compose the message even if a equals 1? Lua doesn't do lazy
>> >> evaluation.
>> >
>> > It would call `tostring(a)` in all cases, but it would not call `string.format` because that branch of the `if` would never be evaluated.
>> >
>> > I am not entirely sure if there is a real performance gain, though.
>>
>> Not only the cost of running string.format, but also memory:
>>
>> for i = 1, N do
>> local a = do_something(i)
>> assert(a == 1, ("`a` should be `%d`, but was `%s`"):format(1,a))
>> end
>>
>> This produces N strings in memory to be garbage collected (adding time
>> to GC runs), while this doesn't:
>>
>> for i = 1, n do
>> local a = do_something(i)
>> format_assert(a == 1, "`a` should be `%d`, but was `%s`", 1, a)
>> end
>>
>> (Note the removed tostring(), or else we'd still get N strings; so if
>> necessary the implementation of format_assert should do that instead.)
>
> And then a isn't a string or a number and you get another error while
> trying to log an error; calling tostring() is safer.
I did explicitly say that tostring() should be called inside the implementation
of format_assert. Does it complicate the implementation of format_assert?
For sure. But the implementation of format_assert does not need to be simple
or fast. The overhead of non-failing asserts must be small.
> But if you are really concerned about GC and performance, you'll need to
> force lazy evaluation on this:
>
> format_assert(a == 1 , function()
> return ("'a' should be %d, but was '%s'"):format(1,tostring(a)))
> end)
>
> This is assuming that format_assert() can check if the second parameter is a
> function and call it. Doing it this way, the string isn't constructed until
> it's needed (that's what lazy evaluation is).
And you'll be creating a closure each time this line runs, which is
even worse. (And yes, I know about closure caching in Lua 5.2+ — it
won't save you every time.)
Also, I happen to know what lazy evaluation is. There's plenty of
Haskell in my Github repo.
-- Hisham