Documentation of user-defined predicates in the prolog lsp-server

Thanks Jan, also tested the problem reported in Text help fails in some cases, and it is solved.

Pushed a little more elegant solution that preserves this annotation.

Tested on my complete source, and seems good.

If my source has set_prolog_flag(autoload,false), and I turn autoload on after loading it (and warn_autoload is also set), I get this:

?- set_prolog_flag(autoload,true).
true.

?- help(transform_kythe_fact/2).
Warning: /home/peter/src/pykythe/pykythe/pykythe.pl:1151:
Warning:    Auto-loading re_replace/4 from library(pcre) into module '$xref_tmp' is deprecated due to term- or goal-expansion
/home/peter/src/pykythe/pykythe/pykythe.pl


 transform_kythe_fact(+Fact0, -Fact1) is det[private]
    TODO: Note that this also changes fact_value to  base64 and  has special
    cases for symtab, text, colors
true.

A quick search tells me this is causes by the cross-referencing module while trying to get (meta-)predicate properties. It is sure this is not desirable, but it is less clear what to do. Surely the cross referencer should remain silent. What about predicate_property/2 in general though? The idea behind the warning is that if a library defines public term/goal expansion, this may be necessary for proper operation and thus it is unsafe to call predicates from it using autoloading. Does that also apply to getting a predicate property?

Note that libraries that define some “predicate” using goal expansion also define the predicate itself. If it can only be used through the expansion, the implementation throws an error. In some cases, the expanded and runtime version have different semantics (library(yall)). This is rather undesirable. In most cases the runtime version is merely slower. Having a predicate though allows program analysis and documentation to work.

I’m not sure what predicate_property/2 should do in this situation. But library(pcre) should have already been loaded by the use_module/2 directive, so there shouldn’t be any auto-loading warnings. Also, the error message (“into module ‘$xref_tmp’”) is confusing.

There seem to be bugs in predicate_property/2, and they occur whether library(pcre) is autoloaded or explicitly loaded with use_module/2:

  • imported_from gives yall instead of pcre
  • line_count seems wrong – and is it actually supposed to be the line number of the predicate, as the documentation says?
  • size seems wrong
  • number_of_clauses is wrong (I tested with pcre:split_range_regex/2, which has two => clauses; I also tried user:goal_expansion/2, which also didn’t have multifile set)

Both line_count and size give the same result for all the predicates in library(pcre), whether they’re in Prolog or C.

?- forall(predicate_property(re_match/2, Z), writeln(Z)).
interpreted
visible
static
imported_from(yall)
transparent
meta_predicate? / 0
file(/home/peter/.local/lib/swipl/library/yall.pl)
line_count(275)
number_of_clauses(1)
number_of_rules(1)
last_modified_generation(5718)
defined
size(392)
true.

Peter, see the comment by @LogicalCapitain on the doc page.
You get library(yall) as a result because you’re asking for the predicate (/)/2, actually autoloaded from library(yall).

2 Likes

Great catch. This is a good example of how “types” as in other languages don’t really fit neatly in Prolog (I am referring to this discussion). More strict typing should catch such typos/thinkos, one would hope, but in fact both can be correct in some scenario. Same goes for syntactic sugar as discussed higher in the same thread.

But why is only re_replace/4 triggering this? There are a couple of meta-predicates in library(pcre), but re_replace/4 isn’t one of them.

Also, the goal expansion is only for re_match/2 and re_match/3, not re_replace/4 (and it’s controlled by a re_compile flag).
(Goal expansion probably should be done for re_replace/4, as well as for most of the other predicates in the library.)

@jan – please point me to the code that’s doing the cross-referencing.

This has bitten me in the past; but I had completely forgotten. :frowning:

Check out library(prolog_xref). Search for xref_tmp.

The warning only checks that the library installs clauses for global expansion hooks. Not what they do. That is in general hard to figure out. For many of these libraries, some of the predicates work perfectly with autoloading and in most cases for the others the result should be merely slower. Sometimes much slower though :frowning:

I think that the most elegant solution is for the autoloading by predicate_property/2 to ignore the warn_autoload flag. The next question is “how”.

For the cross-referencer we want no such warnings anyway. Pushed a commit that silences these warnings of the xref flag is set. This flag is set when cross-referencing a file and notably allows some expansions to not do their work when cross-referencing. This typically applies to “dirty” expansions that have side-effects.

Me too :frowning: There is not much we can do though. Possibly yall should only be implemented using expansion. Then we still need the predicates for analysis and documentation though and (I guess) yall will stop working in interactive queries. So, not great either :frowning:

Possibly yall shouldn’t be autoloaded. :slight_smile:
[Although this will probably break some existing code …]

yall defines expansions for >> and /, both of which have builtin meanings (in is/2). If I didn’t know about library(yall) and was reading some code that used these, I’d be very confused. If library(yall) required being explicitly loaded, that would be overall beneficial (IMHO, YMMV, etc.)
[Disclaimer: I’m from the “be explicit (with occasional exceptions to reduce verbosity)” school of large-scale programming, So, I don’t like C++ using-directives or Python import *. Some people say "but a good IDE will help you read the code; but I don’t always have a good IDE available.]

Possibly. On the other hand, there are people who like using it at the toplevel. Of course, they can add it to their init.pl

As we have seen in another ongoing discussion, terms have different meaning in different contexts in Prolog. That may be confusing to new users. It also allows for a lot of nice things :slight_smile:

Anyway, the plan is to first introduce the warn_autoload flag defaulting to true when this flag functions properly. After that we may consider to remove yall from the autoload list.

use_module(library(yall)) works at the top level. :slight_smile:

Indeed. I should have thought of trying help(/) when I got the strange results from predicate_property(foo/2, P), but I didn’t. (Maybe predicate_property/2 can be “enhanced” to allow the foo/2 form of “head” that current_predicate/1 uses.)