Clearing up confusion Lassi Kortela (14 Aug 2020 15:12 UTC)
Re: Clearing up confusion John Cowan (15 Aug 2020 00:54 UTC)
Re: Clearing up confusion Marc Nieper-Wißkirchen (15 Aug 2020 10:47 UTC)
Clearing up the previous clearing up Lassi Kortela (15 Aug 2020 11:46 UTC)
Re: Clearing up the previous clearing up John Cowan (15 Aug 2020 15:03 UTC)
Re: Clearing up confusion hga@xxxxxx (15 Aug 2020 20:23 UTC)

Clearing up the previous clearing up Lassi Kortela 15 Aug 2020 11:46 UTC

> You seem to be flip-flopping here in a way I find hard to understand.

I replied too hastily and misread your and Harold's suggestions, adding
to the confusion instead of clearing it up.

>      > If a universal set of facility names is off the table, then Posix
>     errors
>      > could be recognized by an 'errno key, whose value is the numeric
>     error.
>
>     That sounds exactly right to me.  [1]
>
> Here at [1] you are saying "Detect a Posix error by looking for the
> 'errno key."
>
>     If a procedure in 170 is implementated using POSIX or a POSIX emulation
>     library like cygwin, it should return something like
>     (make-foreign-error
>     'set 'errno 'number 2 'name 'ENOENT 'message "No such file or
>     directory"
>     ...) as John suggests. [2]
>
>
> Here at [2] you are saying "Detect a Posix error by looking at the value
> of the 'set key".

That inconsistency is due to my misreading.

>     Adding error-handling procedures into 170 is probably not useful.
>
> The two procedures I've added to 3.1 are tentative, just in case 170
> finalizes long before 198 (which begins to look likely, given that 170
> is locking down and 198 is still wildly unstable).  They are just
> convenience procedures layered over 198.

OK. Let's see how the situation develops. We'll end up with something
reasonable.

>     (All we need to mandate is that 170 errors be raised
>     as 198 foreign-error objects.
>
> Absolutely.
>
>     The error handler can check (eq? 'errno
>     (foreign-error-ref st 'set)) and (eq? 'windows (foreign-error-ref st
>     'set)) and things like that. [3]
>
>
> But now, here at [3] you are back to the situation at [1]!
>
>     In particular, I'd stay with the generic 'set and 'number keys [4]
>
> And now, though we are still at the [1] and [3] situation, we have now
> switched from having an 'errno key (as at [1]) to using the generic
> 'number key!!

Again confusing due to my misreadings.

> DECISIONS MUST BE MADE!

We have enough time to make a good decision. Lisp is about prioritizing
the long-term view over quick wins.

> However, I do in fact have an argument for always having a 'set
> available (design [1]): it improves encapsulation.  A guard that catches
> various sorts of errors can be written like this:
>
> (guard e
>    (let ((set (foreign-status-ref e 'set)))
>      ((eqv? set 'posix) (posix-handler e))
>      ((eqv? set 'windows) (windows-handler e))
>      ((eqv? set 'postgresql) (postgresql-handler e))
>      ...))
>
> This guard expression knows nothing about the internals of Posix,
> Windows, Postgresql, etc. error objects: all that knowledge is
> encapsulated in the various *-handler procedures.

That's a good design. foreign-status-ref should return #f for missing
properties. Then 'set doesn't need to be mandatory.

> But using design [2], the guard expression would have to read:
>
> (guard e
>      ((foreign-status-ref e 'errno) (posix-handler e))
>      ((eqv? (foreign-status-ref e 'set) (windows-handler e))
>      ((foreign-status-ref e 'sqlstate) (database-handler e))
>      [...])
>
> Not only is this not encapsulated, the database-handler gets informed of
> PostgreSQL errors but not of SQLite errors.  It's a total mess.
>
> By the simple action of making 'set guaranteed to be available, the
> first guard expression becomes practical and scalable.

A 'set value has always been guaranteed by virtue of the #f default.

The following is my current proposal without the misunderstandings.

Errors coming from a POSIX or POSIX-emulating C API:

'(set     errno
   number  13
   symbol  EACCES
   errno   EACCES
   message "Permission denied")

Errors coming from Windows API:

'(set     windows
   number  5
   symbol  ERROR_ACCESS_DENIED
   errno   EACCES
   message "Access denied")

Errors coming from PostgreSQL:

'(set      postgresql
   number   #f                     ; default value by omission
   symbol   protocol_violation
   message  "Protocol violation"
   sqlstate "08P01")

The 'errno key is independent of 'set, and means "errno equivalent". It
could be filled in for any error coming from any source that has is
roughly equivalent to a particular errno value. We should encourage SRFI
170 implementations to fill it in whenever possible, but should not
mandate it since there will inevitably be weird situations where no
matching errno value exists.

As for detecting "a POSIX error" vs "a non-POSIX error", I'm not sure
that distinction makes sense. '(set errno) tells you the error came from
the C errno variable. '(errno EFOO) tells you that no matter where the
error came from, it means roughly the same thing as the given errno
value; if you additionally care where the error came from, look at the
'set property.

I'd write your guard something like this:

(guard
     (e
      ((eq? 'errno   (foreign-status-ref e 'set)) (posix-handler    e))
      ((eq? 'windows (foreign-status-ref e 'set)) (windows-handler  e))
      ((foreign-status-ref e 'sqlstate)           (database-handler e))
      ...)
   ...)

In most practical situations you probably wouldn't care that the error
comes from POSIX specifically, but only what it means. For example:

(define (read-symlink-if-exists path)
   (guard (e ((eq? 'ENOENT (foreign-status-ref e 'errno)) #f))
     (read-symlink path)))

Again, 'errno like all other properties defaults to #f so testing
arbitrary properties for eq? to some symbol is safe.