Bart Demoen made a petty criticism of between_aux/3 in my sample implementation of between/3. He continues: Conclusion: between_aux/3 is _not_ steadfast. The invariant that _your_ code imposes, can be violated by others in the same module. Steadfastness is all about the INTERFACE seen by USERS of modules. The point is that to the extent practical, users of Prolog modules should see predicates that act logically; when that doesn't make sense (predicates that are supposed to change the state, for example) they should still see predicates that are "clean" in whatever sense is appropriate.
It is entirely commonplace for modules in all sorts of languages to have internal operations which *could* do bad things but *don't* because the rest of the module ensures that they are never called in bad ways.
It is important that beween/3 should be steadfast, because it is an exported predicate.
It is important that between_aux/3 should be steadfast-in-context. For this purpose, it is idle chatter to talk about what other predicates in the module COULD do; they don't. Yes, a change to the module could introduce a bad call. But a change to the module could erase all the files on your disc.
The module this is drawn from is 99 SLOC. between_aux/3 (actually called between1/3 in the code) is *documented* as being an internal part of between/3 and aside from recursive calls is called in precisely one place. It is precisely as steadfast as it needs to be.
One thing I've often wished for in Prolog generally is the ability to make one or more predicates private to another predicate or predicates. In my early days at Edinburgh, I used to indent my code to depict the nesting that I would have liked.
In a functional language, I'd write let <local defs> in <public defs> end so let's rewrite between/3 like this:
:- let.
between_aux(L, U, X) :- ( L =:= U -> X = L ; X = L ; M is 1 + M, between_aux(M, U, X) ).
:- in.
between(L, U, X) :- ( integer(L), integer(U) -> ( integer(X) -> L =< X, X =< U ; var(X) -> L =< U, between_aux(L, U, X) ; <<diagnose and report type failure in X>> ) ; integer(L), var(U), integer(X), X < L -> fail ; integer(U), var(L), integer(X), X > U -> fail ; <<diagnose and report type error or instantiation fault>> ).
:- end.
Think of the :-let part as a "mini module" which can only be imported by the :-in part.
Let's look at the official definition of steadfastness, on page 96 of The Craft of Prolog:
'We want our predicates to be "constant, firm, unwavering" about giving the right answers; we call the property of refusing to give wrong answers even when the query has an unexpected form (typically, as here, supply values for what we normally think of as [outputs]) _steadfastness_ and say that a good predicate is _steadfast_.'
Yes, there's a typo in there. [outputs] reads 'inputs', which doesn't make sense. 'outputs' is what it _should_ say.
Now, since between_aux/3 is a private predicate of a module, ALL THE CALLS TO IT ARE KNOWN. Queries of "unexpected form" do not arise, so on a strict construal between_aux/3 is trivially steadfast.
If someone wants to get picky about whether an encapsulated predicate with only one call is "steadfast" according to some other definition, well, let them. It doesn't matter. The *point* of encapsulating things in modules is to give us the freedom to concentrate interface issues (like argument checking and steadfastness in general) in interface predicates, and to strip purely internal predicates to just the aspects they need to do their highly constrained job. ============================================================================== Message: Address: Action: help majordomo(a)clip.dia.fi.upm.es Info. on useful commands subscribe ciao-users-request(a)clip.dia.fi.upm.es Subscribe to this list unsubscribe ciao-users-request(a)clip.dia.fi.upm.es Unsubscribe from this list <whatever> ciao-users(a)clip.dia.fi.upm.es Send message to list ----------------------------------------------------------------------------- Archived messages: http://www.clip.dia.fi.upm.es/Mail/ciao-users/ -----------------------------------------------------------------------------
Richard has been advocating for ages the writing of steadfast predicates: he could be named the prophet of steadfastness.
So, when Richard writes in a public forum a predicate that does not look steadfast, he should expect remarks. Now, let's not pretend either of us is stupid: I knew about the intended encapsulation and that the way Richard's code uses it, is safe. And he knew I knew that. A real cool answer from Richard after my first remark, would have been along the lines:
# Bart, as usual, you make such fuzz out of nothing, but actually, # you are right, between_aux/3 is not steadfast. Here is a # steadfast version: # # <steadfast version of between_aux/3> # # However, since between_aux/3 is meant to be private to between/3, # its non-steadfastness does not matter <and dwell in it> # <and mock me a little if he really felt like it>
Instead, Richard's first answer was rather disappointing because it started by stating that between_aux/3 is steadfast. (and also because he forgot to mention that my remark was petty :-)
His second answer uses the "official definition of steadfastness". That definition was written at a moment that there was no standard about Prolog modules and where Prolog systems with modules typically allowed to bypass the intended hiding of non-exported predicates: every module (and toplevel) could call between_aux/3 by qualifying it with the appropriate module (most widely used Prolog systems with modules still allow so today).
This means that in the context in which the "official definition of steadfastness" was written, it was clearly not true that "Queries of "unexpected form" do not arise": they did (and they still do) and neither is "ALL THE CALLS TO IT [between_aux/3] ARE KNOWN".
If Richard wants to amend his definition to a (perhaps future) version of Prolog that conforms more to his ideal, fine of course. But the explicit or implied accusation of using some other definition of "steadfast", does not apply to me.
Again, I know what sort of reaction I am hoping for ...
Cheers
Bart Demoen ============================================================================== Message: Address: Action: help majordomo(a)clip.dia.fi.upm.es Info. on useful commands subscribe ciao-users-request(a)clip.dia.fi.upm.es Subscribe to this list unsubscribe ciao-users-request(a)clip.dia.fi.upm.es Unsubscribe from this list <whatever> ciao-users(a)clip.dia.fi.upm.es Send message to list ----------------------------------------------------------------------------- Archived messages: http://www.clip.dia.fi.upm.es/Mail/ciao-users/ -----------------------------------------------------------------------------