From: Harald Hanche-Olsen
Subject: ASDF and reader syntax
Date: 
Message-ID: <pco64jg1udt.fsf@shuttle.math.ntnu.no>
I tend to run my Lisp images with this setting:

(setf (readtable-case *readtable*) :invert)

which works really well, almost all of the time.

It is the exceptions that concern me.

If a system really depends on the usual reader syntax
(readtable-case *readtable*) => :upcase, whose responsibility should
it be to ensure that such is the case?

I suppose I could do it myself, wrapping every (asdf:oos ...) in a
WITH-STANDARD-IO-SYNTAX form.  Or I could write an :around method for
adsf:perform to the same effect. (I could, couldn't I?.  I am not that
familiar with ASDF internals.)  Perhaps it is too much to expect of
the system's author to ensure that his files are loaded with standard
i/o syntax.

Or could it be that the ASDF system itself really ought to take care
of it?  Perhaps it really should wrap every LOAD and COMPILE-FILE form
in a WITH-STANDARD-IO-SYNTAX form?


(For the curious: I have this problem with the system clsql-mysql,
which uses uffi.  If I don't make sure to have the upcasing
readtable-case when loading clsql-mysql, then some foreign function
names wind up with the wrong case.)

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell

From: R. Mattes
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <pan.2006.06.04.21.52.46.585313@mh-freiburg.de>
On Sun, 04 Jun 2006 23:30:22 +0200, Harald Hanche-Olsen wrote:

> I tend to run my Lisp images with this setting:
> 
> (setf (readtable-case *readtable*) :invert)
> 
> which works really well, almost all of the time.
> 
> It is the exceptions that concern me.
> 
> If a system really depends on the usual reader syntax
> (readtable-case *readtable*) => :upcase, whose responsibility should
> it be to ensure that such is the case?
> 
> I suppose I could do it myself, wrapping every (asdf:oos ...) in a
> WITH-STANDARD-IO-SYNTAX form.  Or I could write an :around method for
> adsf:perform to the same effect. (I could, couldn't I?.  I am not that
> familiar with ASDF internals.) 

I fear this won't work -- case conversion is done during _read_ time while
before/after/arround method invocation is done at runtime.

Cheers Ralf Mattes
From: Nikodemus Siivola
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <1149475929.644536.163600@c74g2000cwc.googlegroups.com>
R. Mattes wrote:

> > I suppose I could do it myself, wrapping every (asdf:oos ...) in a
> > WITH-STANDARD-IO-SYNTAX form.  Or I could write an :around method for
> > adsf:perform to the same effect. (I could, couldn't I?.  I am not that
> > familiar with ASDF internals.)
>
> I fear this won't work -- case conversion is done during _read_ time while
> before/after/arround method invocation is done at runtime.

Actually an :around method on compile-op/load-op should work just fine.

Cheers,

  -- Nikodemus Siivola
From: Nikodemus Siivola
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <1149504283.406286.61670@g10g2000cwb.googlegroups.com>
Nikodemus Siivola wrote:

> Actually an :around method on compile-op/load-op should work just fine.

(Unless the code that depends on the reader behaviour is in the .asd
itself,
of course.)

Cheers,

 -- Nikodemus Siivola
From: Ralf Mattes
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <44841A1D.7040304@mh-freiburg.de>
Nikodemus Siivola wrote:
> R. Mattes wrote:
> 
> 
>>>I suppose I could do it myself, wrapping every (asdf:oos ...) in a
>>>WITH-STANDARD-IO-SYNTAX form.  Or I could write an :around method for
>>>adsf:perform to the same effect. (I could, couldn't I?.  I am not that
>>>familiar with ASDF internals.)
>>
>>I fear this won't work -- case conversion is done during _read_ time while
>>before/after/arround method invocation is done at runtime.
> 
> 
> Actually an :around method on compile-op/load-op should work just fine.

Hi Nikodemus,

when would the reader be involved during a FASL-load?

  Cheers, RalfD

> Cheers,
> 
>   -- Nikodemus Siivola
> 
From: Christophe Rhodes
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <sq1wu3kbav.fsf@cam.ac.uk>
Ralf Mattes <··@mh-freiburg.de> writes:

> Nikodemus Siivola wrote:
>> R. Mattes wrote:
>>> [someone else:]
>>>>I suppose I could do it myself, wrapping every (asdf:oos ...) in a
>>>>WITH-STANDARD-IO-SYNTAX form.  Or I could write an :around method for
>>>>adsf:perform to the same effect. (I could, couldn't I?.  I am not that
>>>>familiar with ASDF internals.)
>>>
>>>I fear this won't work -- case conversion is done during _read_ time while
>>>before/after/arround method invocation is done at runtime.

This is gibberish, of course, because the run-time of the asdf:perform
method is the compile-time (implicitly read-time) of the code being
compiled using ASDF.

>> Actually an :around method on compile-op/load-op should work just
>> fine.
>
> when would the reader be involved during a FASL-load?

When executing top-level forms which involve the reader or printer.
(I suspect it's more common to involve the reader at compile time,
which for files includes read-time).

Nikodemus is quite correct that methods on asdf:perform can be used to
set reader state (including case mode) around compilation and loading
of files in such a way as to deal with case requirements of code,
though this only solves the issue when using asdf to perform the
compilation and/or load.

Christophe
From: Christophe Rhodes
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <sqvergyosj.fsf@cam.ac.uk>
Harald Hanche-Olsen <······@math.ntnu.no> writes:

> If a system really depends on the usual reader syntax
> (readtable-case *readtable*) => :upcase, whose responsibility should
> it be to ensure that such is the case?

You've suggested som possibilities: your responsibility, asdf's
responsibility.  You haven't actually suggested that it's the code
itself's responsibility, but I think that's my preferred answer; what
you have found is a bug, pure and simple, and it should be fixed in
the code itself, by wrapping WITH-STANDARD-IO-SYNTAX (or whatever)
around the piece of code that depends on standard IO syntax.

Christophe
From: Mark Wooding
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <slrne88is4.gab.mdw@metalzone.distorted.org.uk>
Christophe Rhodes <·····@cam.ac.uk> wrote:

> [...] it should be fixed in the code itself, by wrapping
> WITH-STANDARD-IO-SYNTAX (or whatever) around the piece of code that
> depends on standard IO syntax.

I presume you also believe that code which breaks when *PRINT-CASE* is
set to some non-default value (say, :DOWNCASE -- which is what I usually
use, to stop Lisp shouting at me) is broken.  If so, that's cool.  ;-)

But I think I have to disagree with your starting point.  I think the
main problem with it is that, without making some sort of reasonableness
assumption about the current readable, it's not possible to write text
which reads as (WITH-STANDARD-IO-SYNTAX ...).

Suppose I set the READTABLE-CASE to :DOWNCASE -- would you think it was
acceptable to require all systems to wrap themselves in
(|WITH-STANDARD-IO-SYNTAX| ...)?

Suppose the initial readtable was screwed more vigorously -- say by
making ( and ) be constituent characters and [...] construct lists.  Now
it's impossible to write a form which works in both the standard
readable and this funny one.

I just don't see where the dividing lines have to go, unless we make it
really simple and say that it's ASDF's responsibility to make the
environment be sane.  And I think that probably ought to include
*PRINT-CASE* too.  (It's just too much pain to say it's the user's
responsibility.)

-- [mdw]
From: Christophe Rhodes
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <sqslmjindt.fsf@cam.ac.uk>
Mark Wooding <···@distorted.org.uk> writes:

> Christophe Rhodes <·····@cam.ac.uk> wrote:
>
>> [...] it should be fixed in the code itself, by wrapping
>> WITH-STANDARD-IO-SYNTAX (or whatever) around the piece of code that
>> depends on standard IO syntax.
>
> I presume you also believe that code which breaks when *PRINT-CASE* is
> set to some non-default value (say, :DOWNCASE -- which is what I usually
> use, to stop Lisp shouting at me) is broken.  If so, that's cool.  ;-)

I think setting (readtable-case *readtable*) to :invert is a better
solution to the SHOUTING PROBLEM, but YMMV.

> But I think I have to disagree with your starting point.  I think the
> main problem with it is that, without making some sort of reasonableness
> assumption about the current readable, it's not possible to write text
> which reads as (WITH-STANDARD-IO-SYNTAX ...).
>
> Suppose I set the READTABLE-CASE to :DOWNCASE -- would you think it was
> acceptable to require all systems to wrap themselves in
> (|WITH-STANDARD-IO-SYNTAX| ...)?

No.  (I am happy to put arbitrary lines down in the sand.)

It looks like there is an established convention in the bits of the
Common Lisp world that I can see from here: that program text is
basically in lowercase, and that when there are exceptions to this the
exception is consistent -- that is, the same use of capitalizations
happen everywhere.  There are exceptions, of course; Maxima is (was?
They were talking about the "great downcasification" a while ago) one
that I am aware of, and doubtless there are still pieces of code out
there which do something like

  ;; this is an important function!
  (defun FOO (x y) ...)
  ...
  (defun bar (x) (foo x x))

but I think that the general body of code being distributed out there
these days is broadly lowercase.  (A quick, unscientific poll of 1
million lines of distributed lisp code that I have to hand reveals 12
lines matching 'def.*[A-Z]', of which 8 are false positives.)

Given this (and the case requirements of undistributed code don't
really matter, because with undistributed code you can mandate case
policy as a matter of overall policy), I think it's reasonable to say
that reasonable values for (readtable-case *readtable*) when code is
read are :upcase and :invert.  So I think that it's reasonable not to
have to use |WITH-STANDARD-IO-SYNTAX| to protect code which is in
lowercase.

However, I think that the situation is different when we talk about
code being /executed/: once it has been compiled, there are still
dependencies on case mode, *print-case* and the like in calls to READ
(and READ-FROM-STRING), the ~A and ~S (and other) directives to
FORMAT, and so on, and I think that here there is much, much less of
an excuse to depend on what most code does.  Basically, the point is
that code which calls the reader or the printer itself doesn't a
priori know about its entire dynamic environment, but it is also
extremely well-placed to eliminate that uncertainty itself, for
instance by wrapping WITH-STANDARD-IO-SYNTAX around itself.

As an example, many pieces of code create new symbols by doing things
like

  (macrolet
      ((def (thing) 
         `(defun ,(intern (format nil "MAKE-~A-FROBNICATOR" thing) *package*) (x)
            (lambda (&rest args) (apply #'frobnicate ',thing x args)))))
    (def foo)
    (def bar))

and suddenly we've introduced a compile-time dependency on
*print-case* being what we expected it to be, where that dependency is
completely unnecessary, as we could have used
  (format nil "MAKE-~A-FROBNICATOR" (symbol-name thing))
or
  (with-standard-io-syntax (format nil "MAKE-~A-FROBNICATOR" thing))
or even
  (concatenate 'string (symbol-name '#:make-) 
                       (symbol-name thing) 
                       (symbol-name #:-frobnicator))
which are insensitive to the user's preferences for printing.  (It is
this kind of thing which I assume the OP was referring to.)

Far worse even than this are pieces of code which perform this kind of
operation at run-time for the application, where there really
shouldn't be any expectation at all that the user's dynamic state
preferences are the same as were in force when the user compiled the
code, let alone when the developer developed the code; for an example
of this, consider a DEFCLASS*-style macro which generates FOO-OF
accessors for slots of name FOO; if this macro depends on the user's
case preferences for correct operation, I would not hesitate to call
it broken.

Basically, all this boils down to is to insulate yourself from changes
to dynamic variables at code execution time from their values at code
read time, and not to worry too much if the user destroys their own
ability to read your code.

Christophe
From: Mark Wooding
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <slrne8dahu.gab.mdw@metalzone.distorted.org.uk>
Christophe Rhodes <·····@cam.ac.uk> wrote:

> I think setting (readtable-case *readtable*) to :invert is a better
> solution to the SHOUTING PROBLEM, but YMMV.

Hmm, could be.

> but I think that the general body of code being distributed out there
> these days is broadly lowercase.  (A quick, unscientific poll of 1
> million lines of distributed lisp code that I have to hand reveals 12
> lines matching 'def.*[A-Z]', of which 8 are false positives.)

I've definitely seen some macro code which would cause problems here.
It followed the convention that macro-level names were lowercase as
usual, and names which were going into the expansion were UPPERCASE.  

I first saw this in the MIT Scheme source, but I think I've also seen it
in various bits of the CMU CL codebase.  It didn't strike me as being a
particularly clever idea, I admit.

> Basically, all this boils down to is to insulate yourself from changes
> to dynamic variables at code execution time from their values at code
> read time, and not to worry too much if the user destroys their own
> ability to read your code.

Fair enough, I suppose.  I think you've persuaded me.

-- [mdw]
From: Harald Hanche-Olsen
Subject: Re: ASDF and reader syntax
Date: 
Message-ID: <pcoy7wb4ev4.fsf@shuttle.math.ntnu.no>
+ Christophe Rhodes <·····@cam.ac.uk>:

| Harald Hanche-Olsen <······@math.ntnu.no> writes:
|
|> If a system really depends on the usual reader syntax
|> (readtable-case *readtable*) => :upcase, whose responsibility should
|> it be to ensure that such is the case?
|
| You've suggested som possibilities: your responsibility, asdf's
| responsibility.  You haven't actually suggested that it's the code
| itself's responsibility,

Let's say I left that possibility for reader to figure out.  8-)

| but I think that's my preferred answer; what you have found is a
| bug, pure and simple, and it should be fixed in the code itself,

That's my thinking too.  Just to be specific, here is the code that
prompted my question, from UFFI's primitive.lisp:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (char= #\a (schar (symbol-name '#:a) 0))
    (pushnew :uffi-lowercase-reader *features*))
  (when (not (string= (symbol-name '#:a)
		      (symbol-name '#:A)))
    (pushnew :uffi-case-sensitive *features*)))

(defun make-lisp-name (name)
  (let ((converted (substitute #\- #\_ name)))
     (intern 
      #+uffi-case-sensitive converted
      #+(and (not uffi-lowercase-reader) (not uffi-case-sensitive))
      (string-upcase converted)
      #+(and uffi-lowercase-reader (not uffi-case-sensitive))
      (string-downcase converted))))

What is not immediately clear is what this code does, namely to create
a Lisp symbol to name the foreign function whose name is given as the
argument.

Assuming the readtable-case was :invert, then when UFFI encounters a C
function like atol64 then the foreign function is named |atol64|, and
this breaks when Lisp code later tries calling the function as atol64
(which is |ATOL64| of course).

But if I temporarily set readtable-case to :upcase while loading this
code, it works correctly.

(Incidentally, the next thing is to delete :uffi-lowercase-reader and
:uffi-case-sensitive from *features*, so they are used only in this
one place.  Seems to me one could have done just as well with a
#. hack or perhaps a macrolet, but never mind that.)

Certainly, this kind of code that detects the user's readtable-case
and tries to adapt will not work at all if ASDF were to enforce
standard syntax around each load or compile-file.  The problem should
probably be solved in a different manner altogether, though I'm not
sure exactly how.  But that's a disucssion perhaps better suited for
the UFFI mailing list.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell