Portable way to check availability of an arithmetic function

I’m trying to check whether a certain arithmetic function (specifically the 2-argument version of log) is available, so that I can conditionally use that function if possible and emulate it otherwise.

The obvious solution would be to just try calling the function and checking if it works or not, like catch(_Res is log(2, 4), _Error, false). Unfortunately this doesn’t always work reliably on SWI - if library(arithmetic) has been loaded, it tries to perform term/goal expansion on the right-hand side of (is)/2, which throws an error on unknown functions. Because the error is thrown during term/goal expansion rather than during execution, it isn’t caught by the catch/3 call.

As a workaround, I rewrote the check to use a meta-call, in the hope of forcing the term/goal expansion to happen inside the catch/3, so that errors from the expansion are caught: Code = (_Res is log(2, 4)), catch(Code, _Error, false). This seems to work (tested with the current development version of SWI built from source), but I’m not sure if this is a reliable way to catch errors from term/goal expansion or if it might break in the future…

SWI-Prolog provides current_arithmetic_function/1 for querying which arithmetic functions are available, but as far as I can tell, this predicate is entirely SWI-specific, so it’s not very useful for writing portable code. I suppose I could first try to use current_arithmetic_function/1, and only if that predicate isn’t available fall back to the catch/3-based check?

I think that is the way to go. ISO doesn’t define a way to find out whether a function is defined except for handling the exception. I would specifically check for type_error(evaluable, name/arity) and provide arguments to the function. If the function exists you may get other errors from the function. Something like this:

current_arithmetic_function(Term) :-
    functor(Term, Name, Arity),
    functor(Gen, Name, Arity),
    foreach(between(1, Arity, I), arg(I, Gen, 1)),
    catch(_ is Gen, Error, true),
    (   var(Error)
    ->  true
    ;   Error = error(type_error(evaluable, Name/Arity))
    ->  false
    ;   true
    ).

Not tested. Doesn’t handle the generating mode of current_arithmetic_function/1 :frowning:

Thanks, I’ll do something along those lines then. Thankfully I don’t need the full functionality of current_arithmetic_function/1 - I only need to check the availability of a specific function, so I can probably skip the skeleton term generation/argument filling part and manually provide a known valid call instead.