guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Announcing 8sync: an asynchronous programming language for Guile


From: Amirouche Boubekki
Subject: Re: Announcing 8sync: an asynchronous programming language for Guile
Date: Sat, 05 Dec 2015 10:46:33 +0100
User-agent: Roundcube Webmail/1.1.2

Le 2015-12-04 03:47, Amirouche Boubekki a écrit :

   Le 2015-12-04 03:15, Amirouche Boubekki a écrit :

       ```
       (define (read/ sock)
         (abort-to-prompt 'loop (lambda (cc)
(loop-add-reader sock (lambda () (cc (read
       sock)))))))
       ```


   This is a mistake, it *must* be a macro


This will only help with debugging but not catching error and
dealing with them at runtime ie. it doesn't propagate the exception
but it can be done and requires a form similar to propagate-%async-exceptions.

TBH the code still seems complex maybe complicated. FWIW here is
what I think right now. Be warned that everything should be taken
with a grain of salt.

* Agenda

** The canonical callback based event loop API is not visible enough

It should be obvious coming from outside Guile world what/where
is the event loop. As such, agenda doesn't seem like a good name.

** Agenda has both `schedule` and `queue`

For a proof of concept, queue/schedule is not useful to demonstrate
the purpose of eightsync as it's an optimization.

** `(current-agenda-prompt)`

No need to throw, there should always be a current agenda.

* <schedule>

Schedule should be in its own file. Also, in place of:

```
(define-record-type <schedule>
  (make-schedule-intern segments)
  schedule?
  (segments schedule-segments set-schedule-segments!))
```

I prefer:

```
(define-record-type <schedule>
  (%make-schedule segments)
  schedule?
  (segments schedule-segments-ref schedule-segments-set!))
```

Use of `*-ref` and `*-set!`.

Or better: `(define-record-type* <schedule> segments)` (actually I
think this macro should be in Guile, since it much easier to
introduce <records> to new devs).

** `time` procedures have equivalent in Guile

*** `tdelta` is not useful.

* `<run-request>`

** `run-it`

It's sound like it's a `(loop-call-soon callback #:optional (delay 0))`
procedure.

Instead it's a `(make-run-request proc #:optional time)`.

It's never used.

I'd rather to use a `delay`, and let the devs compute the correct delay,
when they wants to run something at an absolute time to limit the
proliferation of sugar procedure in the library.

*** `(wrap e ...)` and `(wrap-apply body)`

I'm pretty sure that `wrap` can be written using `wrap-apply`. This looks
suspicious for several reasons.

First it looks like a delayed call, so why not use force/delay.

Also wrap-apply is never used.

I think it's not schemey to hide a lambda this way, especially `wrap-apply`
which breaks lexical scope.

`wrap` is used with `(make-run-request proc time)` in `run`, `run-at`
and `run-delay`, e.g.:

```
(define-syntax-rule (%run-delay body ... delay-time)
  (%run-at body ... (tdelta delay-time)))
```

Again, `run` and others are building a datastructure not registering
a callback so the naming is not good.

* `(make-port-request port #:key read write except)`

In `async.scm` I don't need to create a datastructure to subscribe to select events.

** `port-request` defined at L452 is never used

* %8sync

This is the main macro, here is it's definition:

```
(define-syntax-rule (%8sync async-request)
  (propagate-%async-exceptions
   (abort-to-prompt (current-agenda-prompt) async-request)))
```

I'm wondering whether (current-agenda-prompt) is useful.
I think the code will abort to the prompt of the current dynamic
context. So except if there is multiple agenda in the same thread,
it's not useful.


It's comparable to the way I define blocking procedures in async.scm

```
(define-public (read/ sock)
  (abort-to-prompt 'loop async-request))))
```

where `async-request` is in `async.scm`:

```
(lambda (cc) (loop-add-reader sock (lambda () (cc (read sock)))))
```

It's the way `async.scm` does blocking calls (and *only* blocking calls). `read/` and its `async-request` is missing catch around `read` and something
like `propagate-%async-exceptions`.

8sync has two types of async-request:

** run-requests, which implements kind of a *coroutine* behavior.

It pause the execution of the current procedure and schedule
the provided lambda to be run soonish; This doesn't exists in
async.scm. The only thing useful this can do, is break the callstack
to allow deeper recursion.

** port-requests, which implements imperative asynchronous calls of blocking operations

** %8sync usage example

```
(%8sync (%run (handle-line socket ready-line username)))
```

Where %run is a macro that implements exception catch,
complementary to `propagate-%async-exceptions`.

** Last note

This doesn't look nice:

```
    (define (ports->procs ports port-map)
      (lambda (initial-procs)
        (fold
         (lambda (port prev)
           (cons (lambda ()
                   ((hash-ref port-map port) port))
                 prev))
         initial-procs
         ports)))
```

then:

```
       ((compose (ports->procs
                  read-ports
                  (agenda-read-port-map agenda))
                 (ports->procs
                  write-ports
                  (agenda-write-port-map agenda))
                 (ports->procs
                  except-ports
                  (agenda-except-port-map agenda)))
        '()))))
```

HTH



reply via email to

[Prev in Thread] Current Thread [Next in Thread]