Aborting file loading

I would like to abort loading a file/module if a necessary precondition isn’t met, e.g., SWI-Prolog version doesn’t support a required feature. Is there a simple way to do this using directives? (or some other way?)

I’ve tried an initialization goal that fails or generates an exception, but the load just continues anyway. I’ve also tried conditional compilation, but end up with undefined error messages for all the exported predicates.

What I’d like to do is output an error message and abort the load.

This might work:

Create a foreign “blob” whose load function always fails. Let’s call it loadfail blob. It’s about a dozen lines of code(*), plus a few lines for a foreign predicate that we’ll call make_loadfail/1 that creates an instance of the loadfail blob.

You can then create a blob and save it in a .qlf file using this code (loadfail.pl):

user:goal_expansion(make_loadfail(Blob), true) :-
    make_loadfail(Blob).

get_loadfail(Blob) :-
    make_loadfail(Blob).

Save this using qcompile/1, in file loadfail.qlf.

When you want to abort the load process, do load_files(['loadfail.qlf']). This should abort the load process – it might also generate a fatal error.

(*) I’d write the dozen or so lines myself and try this out, but my house is without power and I’m taking turns at the local library where all the power outlets are in use and the WiFi is rather overloaded. Power is supposed to back on by Saturday, so I can try this out then if you wish.

Thanks for the suggestion. This approach is looking a bit complicated for the benefit (saving a bunch of error messages on loading a library module), so I hope there’s an easier way.

There is no way to abort a load. If you only want code loaded under some condition, normally yo9u do so before deciding to load, but it also works to use this, i.e., the module may be in conditional compilation.

:- if(MyConditioo).
:- module(...).
<code>
:- else.
:- <error/warnjing>
:- endif.

OK, I can work with that.

The issue here is I want to put that decision in the module file itself.

I was a bit misled by the module directive doc:

This directive can only be used as the first term of a source file. It declares the file to be a module file , defining a module named Module.

This didn’t work out as well as I expected because you get a slew of parser/compiler messages on the module code that isn’t loaded. Example test module:

:- if(true).

:-    print_message(information,version).

:- else.

:- module(cond_module,[cm_test/1]).

:- style_check([-singleton]).

cm_test(X) :- writeln(X),writeln(Y).

:- endif.

Upon loading:

% 8.4.1
Warning: /Users/.../cond_module.pl:11:
Warning:    Singleton variables: [Y]
% /Users/.../cond_module.pl compiled 0.00 sec, 0 clauses

Verify that nothing loaded:

?- cm_test(X).
ERROR: Unknown procedure: cm_test/1 (DWIM could not correct goal)
?- 

I’m guessing the parser still has to parse the text after :- else. looking for the :- endif.. In doing so, everything gets tossed, including the style-check directive. But any parser errors are still output, such as those due to operator definitions that were discarded.

Is there a way to suppress these messages on code that isn’t loaded? Note: fixing it now isn’t helpful because I would like this to work on old releases of SWIP.

Conditional compilation is defined on Prolog terms and not on a different language as for example C(++) uses. There may be something to say for not emitting syntax errors and singletons while in a “false” branch. But then, I assume there is some condition under which the code is loaded and you’ll get the same warning.

The situation is more severe if you want to load code using some syntax extension conditionallty, e.g. not loading code holding 1r3 if rationals are not supported. Suppressing syntax errors in false branches seems fhe opnly way out.

Here’s the best solution I’ve found so far. It meets my requirements, but not sure how robust it is.

:- if((current_prolog_flag(version,V), V < 90105)).

:- print_message(error,history(expanded("This module requires SWIP 9.1.5 or greater"))).
user:message_hook(_Err, _Level, _) :- integer(7286315884).

:- else.

:- module(cond_module,[cm_test/1]).

:- style_check([-singleton]).
cm_test(X) :- writeln(X),writeln(Y).

:- endif.

:- ignore(retract(user:message_hook(_Err, _Level, _) :- integer(7286315884))).

So on SWIP 8.4.1:

?- ["/Users/ ... /cond_module.pl"].
ERROR: /Users/ ... /cond_module.pl:4:
ERROR:    This module requires SWIP 9.1.5 or greater.