Getting an initialization error with 10.0.1

Preamble: I’ve been using swi prolog for > 20 years.

I have a top-level module that looks like this:

:- initialization top.

:- use_module(driver).

eval :-
  current_prolog_flag(argv, Argv),
  main(Argv).

top :-
  catch(eval, E, (print_message(error, E), fail)),
  halt.
top :-
  halt(1).

This used to work. But no longer does when I upgraded to 10.0.1

I am on a mac running Tahoe.

Note: the error I get is:

ERROR: [Thread main] /Users/fgm/Projects/star/src/BootCompiler/sbc.pl:1: Initialization goal raised exception:

Note: the offending exception is not displayed.

Note: the program (driver in this case) does run to completion successfully, and does not throw an exception (which I have verified by running interactively)

Suggestions would be welcome. I tried searching both with and without ‘ai’ and no luck.

Cheers,
Francis

This seems to have something to do with the :- initialization directive. I tried using initialization/2 with different second argument. Here is what I see:

:- initialization(top, now).

Initialization goal raised exception: ERROR: '$run_init_goal'/1: Unknown procedure: top/0

:- initialization(top, after_load).

ERROR: [Thread main] Initialization goal raised exception:

(and nothing else, as you reported; this is also documented to be “same as initialization/1”)

Using main or program as the second argument seems to circumvent the problem.

Of course, the error message is misleading. The correct solution is indeed to use initialization/2, preferably with type main. Typically you want to combine that with library(main), which provides Ctrl-C handling and option parsing.

Let me explain what is wrong with initialization/1.

initialization/1 is executed after loading a file. This implies that if you call initialization/1 to run the entry point, you can only do so from the “main” file. Embedding this goal in some indirectly loaded file will cause it to executed before all code is loaded.

The second problem is that SWI-Prolog loads files while protecting against interrupts. This includes running the initialization goals. This is needed to avoid partial lazy loading due to interrupts/timeout.

IMO, initialization/1 only makes sense to perform preparation steps that cannot be part of the compilation process itself.

SWI-Prolog introduced initialization/2 to give more control over when the initialization is performed. Notably :- initialization(mygoal, main). will run the entry point. This is executed after all code is loaded and the interrupt protection is released. The nice thing of this is also that the entry point is not executed if

  • The file was loaded with swipl -l file.pl ...
  • The file was loaded from the interactive toplevel.

This makes debugging and running comfortable. To run, use

 swipl script.pl <script arg ...>

To debug, run

swipl -l script.pl <script arg ...>

Setup your debugging and call the entry point from the toplevel.

I’ve changed the message to

> src/swipl top.pl aap 
Hello aap
Warning: [Thread main] /home/jan/src/swipl-devel/build/top.pl:1: top
Warning: [Thread main]   Initialization goal called halt(0).
Warning: [Thread main]   The program entry point should be called using initialization/2.
Warning: [Thread main]   Consider using library(main).

The problem is the non-standard behaviour. Alternatively we could opt to make the initialization goals for the toplevel script special? I’m afraid that will be a bit fragile though.

Suggestions?

1 Like

Thank you for the guidance.

Has this changed recently?

The fact that you get a misleading error is relatively new. This change was caused by making halt/0 work using an exception and was introduced somewhere in the 9.3.x devel series. The issue that running the entry point from initialization suffers from interrupt issues is much older.