Minimal foreign error API Lassi Kortela (28 Jul 2020 10:28 UTC)
Re: Minimal foreign error API hga@xxxxxx (28 Jul 2020 11:31 UTC)
Re: Minimal foreign error API Lassi Kortela (28 Jul 2020 12:05 UTC)
Re: Minimal foreign error API Lassi Kortela (28 Jul 2020 12:26 UTC)
Re: Minimal foreign error API Lassi Kortela (28 Jul 2020 12:30 UTC)
Re: Minimal foreign error API Lassi Kortela (28 Jul 2020 13:02 UTC)
Re: Minimal foreign error API hga@xxxxxx (28 Jul 2020 17:56 UTC)
Abstract or concrete data type for foreign error object? Lassi Kortela (31 Jul 2020 16:18 UTC)
Re: Abstract or concrete data type for foreign error object? Lassi Kortela (01 Aug 2020 20:10 UTC)
Re: Minimal foreign error API John Cowan (28 Jul 2020 14:39 UTC)
Re: Minimal foreign error API hga@xxxxxx (28 Jul 2020 15:59 UTC)

Re: Minimal foreign error API hga@xxxxxx 28 Jul 2020 17:56 UTC

> From: Lassi Kortela <xxxxxx@lassi.io>
> Date: Tuesday, July 28, 2020 7:05 AM
>
>>> (foreign-error? object) → boolean
>>
>> If they're nothing more than a property list, and I see no reason to
>> make them more complicated, the above would be a bit weak, the best it
>> can do is to make sure it's a plist, or at least a list where you can
>> use standard procedures to confirm there's an 'error-set key, and its
>> value is a symbol.
>
> Ah, I meant merely to specify that the argument list of
> `make-foreign-error` and `raise-foreign-error` is structured like a
> plist, i.e. alternating keys and values. This looks almost as if they
> are keyword arguments.
>
> The `foreign-error` data type would be an abstract data type, so whether
> it internally keeps the plist or turns it into an alist, hash-table or
> record is an implementation detail. Sorry about the confusion.

As I've commented to the point of belaboring, I'm thinking for this
API it would be best if we skip an abstract data type in favor of a
transparent unwrapped plist, keys ordered by make-foreign-error, so
that a human in a REPL without even a pretty printer can make sense of
it.  The only thing I see an abstract data type gaining us is an
absolutely certain version of foreign-error?, and I don't think that's
worth the loss in easy transparency.  As you in part note below:

> In principle, wrapping a define-record-type around the plist would not
> add any value besides the fact that that's the only RnRS-standard way to
> make user-defined opaque data types in Scheme. So maybe it would make
> sense if the bare plist by itself can serve as the error object. Does
> RnRS allow us to `raise` a list as an exception, or does that cause
> problems of some kind?

I don't see any problem based on the text of R7RS, and I just confirmed
Chibi Scheme is happy raising trivial plists.

>> Then again, those *are* the only requirements for a valid error object.
>
> Very good point.
>
> [ Return of raise-foreign-error is undefined. ]
>
>>> (foreign-error-ref ferr property args...) → object
>>>
>>> property is a symbol. If the value of the property is a procedure,
>>> that procedure is applied to args
>>
>> How is the user of a Scheme library supposed to know which args he
>> needs to feed random procedures in the plist??  Message, see below,
>> can be safely special cased, and maybe some others, but the rest??
>
> The point is that the user of an error object shouldn't have to know
> which properties in that object have lambdas and which don't. The
> library writer who makes an error object is responsible for writing any
> lambdas in such a way that they can be given zero arguments and return a
> value that is a reasonable value for that property.

Agreed 100% ... but then why have args above?

One good answer: it allows for a very few (for sanity) values like for
messages to be more sophisticated.  And that can be handled in
Schemeregistry for anything beyond messages.  Or does this allow us
us to punt localization for this SRFI??

> [ More on why 0 arg lambdas are good from your formative experience. ]
>
> [ I unintentionally bike shed args. ]
>
> We could drop support for the `args` argument(s), but that would make
> things like the localization support much more tricky to implement.

Yeah, I'm now much more comfortable with this, as long as we have the
general understanding that they'll be rare, only when a "value" really
justifies args.  Like localization, the only thing we can think of today.

> If the property value is not a lambda, perhaps we should silently ignore
> any `args` given by the user. This would make something like
> `(foreign-error-ref ferr 'message #f)` work even when the message inside
> the error object is a simple string instead of a lambda.

This requires thought, more than I can muster for the rest of today.  It
sounds like a generally right approach for this messy ad hoc domain of
errors.  I can't think of any really bad thing happening.

>>> (foreign-error->string ferr) → string
>>>
>>> Return the error message. Perhaps we can have property for a custom
>>> to-string procedure, and if such a procedure is given in the plist,
>>> that is used instead of the message.
>>
>> Given that it is, and always is going to be a message, wouldn't it
>> be a lot more clear to make the name foreign-error->message?  Does
>> it make sense to use "->", when this form is always? going to return
>> a default string??
>
> `foreign-error->string` is nice for uniformity with other data types,
> e.g. `number->string`.

Veers into "foolish consistency" territory, I think.  It's always going
to be a message thing, right?  And see below where you simplify:

> I'm not sure whether the best thing to return would be the error message
> with nothing added. That's just the most obvious thing.

My conception is that proper full messages are constructed in the plist
handed to make-foreign-error, so nothing further is required (except of
course handling multiple of them for localization).

> The idea would be to return something suitable for `display` and the
> like. Suggestions are welcome.

What's more suitable than a simple string?

"open-file called open: errno/ENOENT: No such file or directory"

In my examples the arguments are behind their own key, but a user of
this SRFI could insert the relevant one(s) in the above message, e.g.:

"open-file called open: errno/ENOENT: No such file or directory "wahFaIh""

> If the return value is always going to be just the message, a simple
> `(foreign-error-ref ferr 'message)` would be enough IMHO.

Yeah, that's completely clear, allows for localization, and removes
one procedure from the API.

>> However, I'll still repeat my point that we can't make alists/plists
>> non-reflective, except for opaque values like procedures, and that
>> however they're constructed, they should have a fixed order, error-set
>> first, the rest....  Instead of my previous idea of complicating the
>> whole system by having the symbol that's the value of the error-set
>> have as its value a list with the order to enforce, any reason to not
>> have make-foreign-error (always called by the raise- procedures, which
>> we should explicitly state) put the plist in alphabetical order by key?
>
> Sure, it's fine for `make-foreign-error` sort the plist (either
> alphabetically, or by some other criteria - e.g. what is the nicest
> order for display purposes). Since foreign-error is an abstract data
> type, it can also do any other processing that is useful to the
> implementation, e.g. convert the plist to an alist or hash-table.

Or do any of the above while [ beats horse with unwrapped plist. ]

>> Even if there's issues with sort orders not being entirely consistent,
>> a particular Scheme implementation instantiation should always do it
>> the same, and that's good enough for my purposes.
>
> Makes sense. Per the plist definition you found in the Common Lisp
> HyperSpec, in case of duplicate plist keys the first key wins.
> `make-foreign-error` should interpret its argument list that way as well.

Indeed.  In the interests of the end user, it *always* produces something
sensible.  If the plist is malformed, or doesn't include an 'error-set
key with a symbol as the value, it emits:

 '(errorset error arguments [whatever its argument ere])

The end user should be able to make *some* sense out of this result.
Error handling tends to be one of the least thoroughly exercised parts
of a program, I don't want to punish the end user for mistakes with
error reporting the library implementor made.

> [ Example code including localizations, when then gets fixed and
>   filled out in subsequent emails. ]

- Harold