# The \`public\` predicate property

**URL:** <https://swi-prolog.discourse.group/t/the-public-predicate-property/3541>\
**Category:** Predicate\
**Created:** [January 30, 2021, 5:20pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541 "2021-01-30T17:20:05Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 30, 2021, 5:20pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/1 "2021-01-30T17:20:05Z")

</div>

According to the manual the `public` predicate directive ([SWI-Prolog -- Manual](https://www.swi-prolog.org/pldoc/man?section=declare)) “has no semantics.” I’m not sure that’s really the case because whenever I reload a module containing user defined arithmetic functions I get a slew of warnings like:

```prolog
Warning: /Users/ ... /functionalarithmetic/dot_arithmetic.pl:145:
Warning: Local definition of user:fill/3 overrides weak import from dot_arithmetic

```

one for each user defined arithmetic function. Each function predicate, e.g., `fill/3` is exported by the module.

In any of my testing, these warnings don’t seem to have any material impact. They seem to be caused when the `arithmetic_function` directive is expanded causing a `:- public(Pred).` to be executed. As a test, I’ve removed this directive from the expansion and the warnings disappear and no ill effects have yet to be noticed.

So what does this directive actually do and will removing it from the expansion of `arithmetic_function` have any ill effects.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 30, 2021, 5:41pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/2 "2021-01-30T17:41:42Z")

</div>

> [@ridgeworks](#):
>
> So what does this directive actually do and will removing it from the expansion of `arithmetic_function` have any ill effects.

It creates the predicate and sets a flag. The flag is only used by a couple of tools. It causes the cross-referencer not to flag the predicate as “not called” and it causes the code obfuscating library not to rename the predicate.

It tells the system that is predicate is called from somewhere, typically either through some callback that cannot be understood by the tools or from a foreign C routine.

If you get this message it may mean the public directive is associated with the predicate in the wrong module and probably some similar situations. It tells you `dot_arithmetic` exports fill/3 that is somehow also defined in user and imported from `dot_arithmetic` using use\_module/1.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 30, 2021, 6:53pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/3 "2021-01-30T18:53:06Z")

</div>

So the only configuration that I can get working is when the arithmetic function is defined in `user` space and the predicate is exported, e.g., something like:

```prolog
:- module(dot_arithmetic, [fill/3]).

:- arithmetic_function(user:fill/2).

fill(Obj, N, Result) :. ...

```

But that produces the warning message when the module is reloaded (not on original consult). AFAIK there are no `use_module` calls involved. Could there be some lingering piece of info left from the previous load?

As I said, there doesn’t seem to be an operational impact, just the confusing warning.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 31, 2021, 8:32am UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/4 "2021-01-31T08:32:34Z")

</div>

The library was a hack … The proper way would be to use

```
:- arithmetic_function(fill/2).

```

And modify the expansion logic such that if fill/2 is imported into the current context fill/2 must be rewritten. That would make the library act properly on the module system. Feel free to submit a PR that makes this work.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [February 1, 2021, 1:52am UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/5 "2021-02-01T01:52:22Z")

</div>

A bit of a learning curve, but very pleased with the final result. All warning messages are gone and I was able to remove a meta-predicate declaration for `arithmetic_expression_evaluation` which was complicating using `:` as a function, e.g., for a slice operation. A few other things were also simplified in the process.

I’ll submit a PR in the next couple of days with my changes after updating the test suite. One thing I noticed is that the current test for `flag/3` is failing, presumably because arithmetic expression in the third argument isn’t being expanded. Should that be fixed as part of this exercise? Any other such cases come to mind?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 1, 2021, 7:45am UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/6 "2021-02-01T07:45:14Z")

</div>

Sounds promising!

> [@ridgeworks](#):
>
> I was able to remove a meta-predicate declaration for `arithmetic_expression_evaluation`

That sounds scary. It is a meta predicate. We’ll see …

For sure the test suite needs to remain passing. In extreme cases that may mean change the test. flag/3 must remain capable of processing arithmetic expressions. I don’t think I care too much about user defined functions. It is mostly used for `flag(f, N, N+1)` to have a rather efficient atomic global counter.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [February 1, 2021, 3:21pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/7 "2021-02-01T15:21:09Z")

</div>

> [@jan](#):
>
> That sounds scary. It is a meta predicate.

Admittedly my understanding of the requirement for the `meta-predicate` directive is a but fuzzy. In this particular case the `call` in arithmetic\_expression\_value is always to a fully module qualified predicate, so there seems to be no reason the expression argument needs to be defined as “meta”. In fact the requirement to derive the “imports from” information, seems to mean there’s no need for the `arithmetic_function` directive to be a meta-predicate either. Seems to all work, but maybe there’s a use case I’m missing.

> [@jan](#):
>
> For sure the test suite needs to remain passing.

If you mean the existing `test_arithfunc.pl`, I can’t believe it’s been working for some time now. It claims to be using module `arithfunc`, although it’s probably getting `arithmetic` via autoloading. And some of the tests are incompatible with `plunit`. Is there some other test suite that is involved here?

> [@jan](#):
>
> It is mostly used for `flag(f, N, N+1)` to have a rather efficient atomic global counter.

In my experience using standard global variables (thread based) and doing your own arithmetic is much more efficient:

```prolog
?- set_flag(x,0),time((between(1,1000000,_),flag(x,N,N+1),fail));get_flag(x,N).
% 6,000,001 inferences, 2.218 CPU in 2.689 seconds (82% CPU, 2705633 Lips)
N = 1000000.

?- nb_setval(x,0),time((between(1,1000000,_),nb_getval(x,X),X1 is X+1,nb_setval(x,X1),fail));nb_getval(x,N).
% 6,000,002 inferences, 0.300 CPU in 0.300 seconds (100% CPU, 20014551 Lips)
N = 1000000.

```

Perhaps it’s for thread safety, but `flag` seems to be extraordinarily slow for what it does.

For efficiency, it would be nice to have something similar using global vars. Even a hard coded increment by `N` for operational measurements would be nice. (OM’s in clpBNR eat up about 4% of the the constraint engine execution time.)

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 1, 2021, 5:05pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/8 "2021-02-01T17:05:30Z")

</div>

> [@ridgeworks](#):
>
> If you mean the existing `test_arithfunc.pl` , I can’t believe it’s been working for some time now. It claims to be using module `arithfunc` , although it’s probably getting `arithmetic` via autoloading. And some of the tests are incompatible with `plunit` . Is there some other test suite that is involved here?

It was indeed very old and not functional as the test was compiled conditionally on a no longer true condition. Thanks. Updated and pushed.

> [@ridgeworks](#):
>
> Perhaps it’s for thread safety, but `flag` seems to be extraordinarily slow for what it does.

? For me the difference is 0.593 sec vs. 0.276 sec. That is on a standard compiled system on Ubuntu 20.04. The main difference is that flags are shared between threads though and global variables are not.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [February 1, 2021, 5:34pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/9 "2021-02-01T17:34:45Z")

</div>

> [@jan](#):
>
> Updated and pushed.

OK. I’ll add my tests to this version in the PR.

> [@jan](#):
>
> For me the difference is 0.593 sec vs. 0.276 sec.

Now that’s interesting - clearly an OS library dependency. Also note the CPU percentage - MacOS version is definitely off in OS land for a significant amount of time. But still a factor of 2 on Ubuntu; hopefully users will know the difference between process globals and per-thread globals.

Per-thread operational measurements are exactly what I need, so it’s a moot point. But I will fix `arithmetic` to expand the `flag` predicate if needed; it’s a trivial addition.

Just curious, is the arithmetic expression in `flag` subject to optimization?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 1, 2021, 5:43pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/10 "2021-02-01T17:43:34Z")

</div>

> [@ridgeworks](#):
>
> But I will fix `arithmetic` to expand the `flag` predicate if needed; it’s a trivial addition.

Wouldn’t bother. I’ve removed the test that verifies this used to work when there were real user defined functions.

> [@ridgeworks](#):
>
> Just curious, is the arithmetic expression in `flag` subject to optimization?

flag/3 is defined in Prolog (`?- edit(flag).`).

```prolog
flag(Name, Old, New) :-
    Old == New,
    !,
    get_flag(Name, Old).
flag(Name, Old, New) :-
    with_mutex('$flag', update_flag(Name, Old, New)).

update_flag(Name, Old, New) :-
    get_flag(Name, Old),
    ( atom(New)
    -> set_flag(Name, New)
    ; Value is New,
        set_flag(Name, Value)
    ).

```

Flags are an old legacy thing of SWI-Prolog. They should be replaced by something better. Well, for most usage there are better alternatives.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [February 1, 2021, 9:27pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/11 "2021-02-01T21:27:16Z")

</div>

> [@jan](#):
>
> Wouldn’t bother. I’ve removed the test that verifies this used to work when there were real user defined functions.

Because of the atomic update, this wasn’t as trivial as I first thought. So not going to happen for now.

> [@jan](#):
>
> [flag/3](https://www.swi-prolog.org/pldoc/doc_for?object=flag/3) is defined in Prolog

So the answer is no (`Value is New`). For efficiency reasons that really seals the deal for per-thread globals if that’s all you need. I do have to wonder why mutex’s are that much slower on MacOS. From my 2009 MacPro:

```prolog
?- time((between(1,1000000,_),Value is 1+1,fail)).
% 2,000,001 inferences, 0.179 CPU in 0.179 seconds (100% CPU, 11154806 Lips)
false.

?- time((between(1,1000000,_),with_mutex('$flag',Value is 1+1),fail)).
% 3,000,001 inferences, 2.288 CPU in 2.862 seconds (80% CPU, 1311235 Lips)
false.

```

Luckily, not a feature I need.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [February 2, 2021, 8:09am UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/12 "2021-02-02T08:09:30Z")

</div>

On Ubuntu, compiled with PGO (Profile Guided Optimization), the difference gets a little bigger as the non-mutex implementation gets faster, but still way below MacOS. Ubuntu 20.04, gcc 9.3.0, AMD 3950X:

```prolog
101 ?- time((between(1,1000000,_),Value is 1+1,fail)).
% 2,000,003 inferences, 0.100 CPU in 0.100 seconds (100% CPU, 20060335 Lips)
false.

102 ?- time((between(1,1000000,_),with_mutex('$flag',Value is 1+1),fail)).
% 3,000,001 inferences, 0.267 CPU in 0.267 seconds (100% CPU, 11256823 Lips)
false.

```

Which version do you use on MacOS these days? The app bundle (compiled using gcc 10 with PGO), Macports? Homebrew? The two latter ones both use MacOS Xcode clang and are a lot slower …

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [February 2, 2021, 2:45pm UTC](https://swi-prolog.discourse.group/t/the-public-predicate-property/3541/13 "2021-02-02T14:45:40Z")

</div>

> [@jan](#):
>
> Which version do you use on MacOS these days?

MacOS 10.13.6 (High Sierra), bundle version of 8.3.18

I’ve remained on High Sierra due to the age of my MacPro (2009, 2.26Ghz Xeon), but it’s very stable and I think general performance is acceptable considering its age. (But my fanless laptop is around 25% faster single threaded.)

Re mutex, the other thing I mentioned is is the CPU utilization. Whereas this little benchmark CPU is 100% on Ubuntu, it’s consistently only around 80% on MacOS. To me this suggests there’s quite a different mutex design strategy on MacOS; it isn’t just a minor optimization issue. This is all a little surprising; mutex is hardly a new concept.

P.S. Interesting how a topic on public predicate directive evolved into a discussion of OS kernel functionality.
