SRFI for ports from arbitrary sources or to arbitrary sinks?
hga@xxxxxx
(19 Sep 2019 11:31 UTC)
|
Re: SRFI for ports from arbitrary sources or to arbitrary sinks?
Lassi Kortela
(19 Sep 2019 12:07 UTC)
|
Re: SRFI for ports from arbitrary sources or to arbitrary sinks?
John Cowan
(20 Sep 2019 17:04 UTC)
|
Re: SRFI for ports from arbitrary sources or to arbitrary sinks? Alaric Snell-Pym (24 Sep 2019 08:38 UTC)
|
Re: SRFI for ports from arbitrary sources or to arbitrary sinks? Alaric Snell-Pym 24 Sep 2019 08:38 UTC
On 20/09/2019 18:04, John Cowan wrote: > But what do we do in Scheme when there's a mismatch between what the SPI > expects and what the plugin provides? There is no formal definition of an > SPI (or any API, for that matter): we cannot even introspect on libraries > to see what they export. Ports are particularly bad in this respect, > because what operations exist may depend on what kind of port this is. > Directory ports in Gambit, for example, are like any other input ports, > except that read returns the next directory entry (doesn't parse > S-expressions at all) and read-char, read-string, read-line just don't > work. Furthermore, if the client API changes, all the plugins break > horribly at run time instead of (as in Java) failing to compile. > > What to do, what to do? I wish I knew. > I imagine something like this: 1. In the SPI library (eg, our DBI) define a record type full of closures to represent a plugin (eg, our DBDs), with all the plugin's. 2. The SPI library hides that record type's constructor and accessors, but exports procedures to invoke the procedures within it, passing in a private data field from the struct as well as the arguments, which is what users of the SPI call: (define (do-thing db x y z) ((db-thing-doer db) (db-private-data db) x y z)) 3. The SPI library also provides constructors for plugins - some combination of different constructors for different levels of functionality and being able to pass in `'#f` for a procedure slot to request default behaviour. Later versions of the SPI will add more constructors to enable more advanced functionality, without changing the names of existing ones, so "old" plugins will still work in some degraded form: (define (make-basic-plugin-instance-v1 private-data thing-doer thang-doer) (make-plugin-instance private-data thing-doer thang-doer (lambda (x) (error "This instance cannot thung")) (lambda (x) (error "This instance cannot thong")))) (define (make-full-plugin-instance-v1 private-data thing-doer thang-doer thung-doer) (make-plugin-instance private-data thing-doer thang-doer thung-doer (lambda (x) (error "This instance cannot thong")))) (define (make-full-plugin-instance-v2 private-data thing-doer thang-doer thung-doer thong-doer) (make-plugin-instance private-data thing-doer thang-doer thung-doer thong-doer)) The "default behaviours" might be to raise an error in this case, or something smarter (perhaps a thong operation can be implemented, inefficiently, as a series of thing and thang operations by default?) 4. Plugins provide constructors that do whatever state construction they need and then call an appropriate make-X-plugin-instance-vY to get a valid plugin instance object. Those constructors are either exported from the DBD module for applications to call directly, or the module body calls a "register" interface in the DBI library to register that constructor under a symbol (I can't remember what we decided about module import side-effects in R7RS) So applications would either do: (import database) (import sqlite) (define db (connect ...)) ;; connect from sqlite (query db ...) ;; query from database or: (import database) (import sqlite) ;; here just to run the module body, no exported ;; bindings used (define db (connect 'sqlite ...)) ;; connect from database Is that a reasonably Schemely approach? -- Alaric Snell-Pym (M7KIT) http://www.snell-pym.org.uk/alaric/