Odd behaviour with ?- expects_dialect(sicstus)

Hi Jan,

Wanted to inform you of odd behaviour (bug) with ?- expects_dialect(sicstus). on current master where atoms are getting unquoted.

Is this merely my local machine or are you or others reproducing this bug?

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.27-27-g9cf6502af)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

1 ?- print('A').
'A'
true.

2 ?- expects_dialect(sicstus).
true.

3 ?- print('A').
A
true.

4 ?-  expects_dialect(swi).
true.

5 ?- print('A').
A
true.

6 ?-

That I am not having this problem with the PPA devel version

Welcome to SWI-Prolog (threaded, 64 bits, version 8.2.4)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- print('A').
'A'
true.

?- expects_dialect(sicstus).
true.

?- print('A').
'A'
true.

?- expects_dialect(swi).
true.

?- print('A').
'A'
true.

On Windows 10 with SWI-Prolog (threaded, 64 bits, version 8.3.27-24-g44c2d0e2d) I get the same as your first example.

On Ubuntu 20.04.2 LTS on WSL 2 with SWI-Prolog (threaded, 64 bits, version 8.3.27) installed as PPA devel version I get the same as your first version. I did not get the same as expected in your second version.

After doing a few builds between of tags I found:
tags/V8.3.22 - Good
tags/V8.3.23 - Broken

Ah, you have a newer PPA than my Debian 10 machine is getting. (Maybe my machine held it back)

@dgelessus ENHANCED: SICStus emulation now disables quoted printing of atoms. · SWI-Prolog/swipl-devel@77d15a2 · GitHub
Looks like you are switching the flag to unquote atoms but not restoring it it back when resuming … Here was some ugly code I used to switch back out of a dialect… logicmoo_workspace/lps.pl at d2b598b9c97215a5d9e836760a0a836fe7404fc2 · logicmoo/logicmoo_workspace · GitHub

@jan We might need a hook to know when a dialect is stopped being used?

Yeah, the solution that I currently implemented here isn’t ideal. As the comment says:

%	This globally modifies the print_write_options Prolog flag,
%	so this change also affects code that doesn't request
%	SICStus compatibility.

This is not just a problem when you explicitly switch back using expects_dialect(swi), but also if non-emulated code loads a module that uses expects_dialect(sicstus). The emulation should automatically switch off again at the end of the file where it was enabled, but the Prolog flag will remain changed.

The codebase that I’m currently working on runs almost completely in expects_dialect(sicstus) mode, so I haven’t looked much at handling this properly yet. An extra hook for disabling the dialect is probably the way to go, as you say, or some other way to restrict a Prolog flag change to only some files.

That said, if I’m reading SWI’s documentation for print/1 correctly, the traditional behavior is that print/1 never quotes atoms, and having it quote where necessary is a SWI-specific change. So ideally, programs that need a specific quoting behavior should avoid print/1 and instead use write/1 or writeq/1 as appropriate, or write_term/2 or format/2 with the desired options.

Of course it’s not always realistic to update all prints like this just to fix the quoting, especially with a large codebase. The code I’m working on has a lot of prints that expect no quoting, so I understand the problem :slight_smile:

1 Like

Main reason for using print/1 for me is that it calls portray/1 hooks that are sensitive the environment they are in for example:

asserta((portray(X):- 
     ​atom(X),
     ( in_html_debugger -> write_atom_hlink(X) ;  writeq(X))). 

will make print('A':'B') will print two hyperlinks separated by a colon in some cases.

Anyways, I was merely surprised … I have a few modules that use sicstus mode and a few that use swi and a few that use other dialects… Of course we should always be ready for portray/1 to change the behaviour of print/1. I was confused as to figuring out which one of my portrays was changing things after I commented them all out.

Yeah… I specifically change stuff back like the operators at the end of the file:

I doubt there is a good solution to this. Indeed, traditionally print/1 does not emit quotes. I think this is wrong. Print/1, using portray/1 is first of all meant for user interaction and notably debugging. All the user-facing tooling (toplevel, debugger, etc.) uses print/1 to print terms. There a were just too many people confused about the exact type of an object that is explicit when quotes are used. Strings make this even worse as it makes "World" and 'World' print the same way.

The main problem with print/portray is that the mechanism is inherently non-modular: any module you may load that adds portray rules may upset the desired way terms are printed.

The normal way to resolve this for a dialect emulation would be to goal expand print/1 to sicstus_print/1 and then hack a little to temporarily redefine it. In most cases though, print/1 is called through format/3, debug/3 or the toplevel and these are unaware that the desired action originates from SICStus code.

Bottom line is that code should not use print/1 if it wants precise control on how the term is emitted unless we are talking about a stand-alone application where we know the code is never to be combined with any other code.

Prolog output is a mess :frowning: Best practice seems to be

  • Use format/3 to emit non-term output
  • When writing a library, use the print_message/2 indirection for talking to the user
  • Use writeq/1 or write_canonical/1 to write terms that need to be read by Prolog.
  • Use portray_clause/1 for listing clauses. This predicate must ensure that reading returns the same clause given the same operator declarations).
  • Use print/1 only for debug/3 and other interactive use of your program.
  • Be careful with portray/1. Only use it for very specific terms for libraries or better, include a dedicated portray library for a specific library. rdf_portray.pl is such as beast for dealing with RDF.
  • write/1 should never have been added to Prolog.
3 Likes