lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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