lua-users home
lua-l archive

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


On 5/17/19, William Ahern <william@25thandclement.com> wrote:
> Most of those throw errors and only return to the immediate caller on
> success, mirroring their Lua counter parts.

in this cases the mere fact that the function returned to the caller means
it succeeded and hence no return value is required to signal the outcome
(but it would not hurt to return one either). i understand.

> This depends on use cases. Whether it's more convenient to signal an error
> through the return value or a separate flag depends on the situation.
> Imagine you're writing a simple integer arithmetic library that handles
> overflow. The obvious way to do this is similar to the GCC and clang
> builtin:
>
>   bool __builtin_add_overflow(type1 x, type2 y, type3 *sum)
>   bool __builtin_mul_overflow(type1 x, type2 y, type3 *prod);
>
> Those are great if you're just performing a single operation. But what you
> need to accumulate the result of 3 add operations and a multiplication?
>
>    int a, b, c, d, e;
>    if (__builtin_add_overflow(1234, 4321, &c))
>      return ERANGE;
>    if (__builtin_add_overflow(9999, &c, &d))
>      return ERANGE;
>    if (__builtin_add_overflow(8888, &d, &e))
>      return ERANGE;
>    if (__builtin_mul_overflow(7777, &e, &result))
>      return ERANGE;
>    return 0;
>
> All those conditionals obscure the math--that's not good code. We could fix
> it slighty like:
>
>    bool overflow = 0;
>    overflow |= __builtin_add_overflow(1234, 4321, &c);
>    overflow |= __builtin_add_overflow(9999, &c, &d);
>    overflow |= __builtin_add_overflow(8888, &d, &e);
>    overflow |= __builtin_mul_overflow(7777, &e, &result);
>    return (overflow)? ERANGE : 0;
>
> But even better might be something like:
>
>    bool overflow = 0;
>    c = __xbuiltin_add_overflow(1234, 4321, &overflow);
>    d = __xbuiltin_add_overflow(9999, &c, &overflow);
>    e = __xbuiltin_add_overflow(8888, &d, &overflow);
>    *result = __xbuiltin_mul_overflow(7777, &e, &overflow);
>    return (overflow)? ERANGE : 0;
>
> If the function names were shorter we might return some evaluations
> directly
> into the function calls of others.
>
> The latter method is how the assembly code usually works, where the result
> of an operation is placed into the destination register and a flag is set in
> a separate, specialized register on overflow. It's also closer to how you
> might organize the code in a higher-level language like Lua. And not
> coincidentally, I think, it's also how lua_tointegerx works.

one could retain functions like
lua_Integer lua_tointegerx ( lua_State * L, int index, int * isnum ) ;
even under their old name. if NULL != isnum it returns the call's result via
the output parameter pointer. why not have both forms ?
the older functions could then be implemented in terms of the new ones,
hence compatibility would be preserved.

> While the Lua C API has some unpleasant artifacts from incremental
> improvements, it's actually much nicer than you seem to give it credit for.
> And in my experience much nicer than the vast majority of APIs I've run
> across.

interesting point, it depends what you compare here. this is definitely true
for python, perl and maybe even tcl and ruby (though those's C APIs are
not that bad, binding code can be written by hand). but what about - say -
Ring(-lang.net), Squirrel(-lang.org), and SGScript(.org) ?
is that still true when comparing with newer languages ?

> I can't disagree about the inconvenience but this is the sort of change
> where the benefit is slight but the backwards incompatibility very painful.
> I normally either write a helper routine or use the pattern found in the
> Lua code itself:
> luaL_argerror(L, arg, lua_pushfstring(L, fmt, x, y));

yes, this works. but isn't the lua_pushfstring function called again
in the underlying
lua_error() call ?