unofficial mirror of bug-guile@gnu.org 
 help / color / mirror / Atom feed
From: Zefram <zefram@fysh.org>
To: 24186@debbugs.gnu.org
Subject: bug#24186: setlocale can't be localised
Date: Mon, 8 Aug 2016 17:32:14 +0100	[thread overview]
Message-ID: <20160808163214.GF24721@fysh.org> (raw)

In Guile 1.8 it was possible to localise the effect of a setlocale
operation, but in Guile 2.0 it's no longer possible by natural use of the
locale API.  This loss of a useful facility is either a bug or something
that needs to be discussed in the documentation.

In Guile 1.8 one could perform a temporary setlocale for the execution of
some piece of code, and revert its effect by another setlocale on unwind.
This looks like:

    (define (call-with-locale cat newval body)
      (let ((oldval #f))
	(dynamic-wind
	  (lambda () (set! oldval (setlocale cat)) (setlocale cat newval))
	  body (lambda () (setlocale cat oldval)))))

Some difficulty arises from this being temporally scoped, where dynamic
or lexical scoping would be nicer, but in single-threaded programs it
works pretty well.  The C setlocale(3) API, after which Guile's setlocale
is modelled, is obviously designed to enable this kind of mechanism: the
read operation reports all relevant state, and the write operation with
the old value sets it all back as it was.  It is critical to this ability
that the read operation does indeed report all the state that will be set.

In Guile 2.0, the setlocale function no longer corresponds so closely to
the C setlocale(3), and this critical guarantee has been lost.  I have
previously reported in bug#22910 that the setlocale read operation
has a side effect on port encoding, and obviously that interferes with
the above code, but actually there's still a problem if that's fixed.
The setlocale *write* operation also affects port encoding (actually
the default port encoding fluid and the encoding of currently-selected
ports), and that seems to be an intentional change, but it also breaks
the above code.  The setlocale read operation doesn't report the encoding
of the currently-selected ports, so doesn't represent everything that
setlocale will set.  The setlocale write operation is not even capable
of setting the port encodings independently: it sets all three to the
encoding nominated by the locale selected for LC_CTYPE purposes.

I think adding this extra effect to setlocale was a mistake.  It doesn't
fit the locale API.  If the extra effect is removed, that would resolve
this problem.

If you really want setlocale to have this effect, then something needs to
be done to address the ability that has been lost.  The documentation
certainly needs to describe the effect on port encoding, which it
currently doesn't.  (There is a mention of some interaction with the
%default-port-encoding fluid in the documentation of that fluid, but it
doesn't match reality: it doesn't say that setlocale writes to the fluid.)
It also ought to specifically warn that the setlocale save-and-restore
dance that works in C doesn't work here.  It should explain what needs
to be done by library functions that want to achieve a localised locale
change.  Are they entirely forbidden to use setlocale?  Are they expected
to manually save and restore port encodings around setlocale calls?
(This is complicated by set-port-encoding! not accepting #f as an encoding
value, despite it actually being a permitted value for the encoding slot.)
Some example code equivalent to the above call-with-locale would be
useful.

-zefram





             reply	other threads:[~2016-08-08 16:32 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-08 16:32 Zefram [this message]
2016-08-08 20:33 ` bug#24186: setlocale can't be localised Andy Wingo
2016-08-08 22:30   ` Zefram
2016-08-09 12:15     ` Zefram
2016-08-09 17:43       ` Andy Wingo
2016-10-11  8:06     ` Ludovic Courtès
2016-10-11 12:49       ` Zefram

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160808163214.GF24721@fysh.org \
    --to=zefram@fysh.org \
    --cc=24186@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).