guix: Use guile-3.0.
[8sync.git] / doc / 8sync.texi
1 \input texinfo   @c -*-texinfo-*-
2 @c %**start of header
3 @setfilename 8sync.info
4 @settitle 8sync
5 @c %**end of header
6 @copying
7 Copyright @copyright{} 2015  Christopher Allan Webber @email{cwebber@@dustycloud.org}
8 @end copying
9
10 @quotation
11 Permission is granted to copy, distribute and/or modify this document
12 under the terms of the GNU Free Documentation License, Version 1.3
13 or any later version published by the Free Software Foundation;
14 with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
15 A copy of the license is included in the section entitled ``GNU
16 Free Documentation License''.
17
18 A copy of the license is also available from the Free Software
19 Foundation Web site at @url{http://www.gnu.org/licenses/fdl.html}.
20
21 Alternately, this document is also available under the Lesser General
22 Public License, version 3 or later, as published by the Free Software
23 Foundation.
24
25 A copy of the license is also available from the Free Software
26 Foundation Web site at @url{http://www.gnu.org/licenses/lgpl.html}.
27 @end quotation
28
29
30 @titlepage
31 @title 8sync
32 @subtitle 8sync, asynchronous actors for Guile
33 @author Christopher Allan Webber
34 @page
35 @vskip 0pt plus 1filll
36 @insertcopying
37 @end titlepage
38
39 @c Output the table of the contents at the beginning.
40 @contents
41
42 @ifnottex
43 @node Top, Preface, (dir), (dir)
44 @top 8sync
45
46 @insertcopying
47 @end ifnottex
48
49 @c Generate the nodes for this menu with `C-c C-u C-m'.
50
51
52 @c Update all node entries with `C-c C-u C-n'.
53 @c Insert new nodes with `C-c C-c n'.
54
55 @menu
56 * Preface::
57 * Tutorial::
58 * API reference::
59 * Systems reference::
60 * Addendum::
61 * Copying This Manual::
62 * Index::
63 @end menu
64
65 \f
66
67 @node Preface
68 @chapter Preface
69
70 Welcome to 8sync's documentation!
71 8sync is an asynchronous programming environment for GNU Guile.
72 (Get it? 8sync? Async??? Quiet your groans, it's a great name!)
73
74 8sync has some nice properties:
75
76 @itemize
77 @item
78 8sync uses the actor model as its fundamental concurrency
79 synchronization mechanism.
80 Since the actor model is a "shared nothing" asynchronous
81 environment, you don't need to worry about deadlocks or other
82 tricky problems common to other asynchronous models.
83 Actors are modular units of code and state which communicate
84 by sending messages to each other.
85 @item
86 If you've done enough asynchronous programming, you're probably
87 familiar with the dreaded term "callback hell".
88 Getting around callback hell usually involves a tradeoff of other,
89 still rather difficult to wrap your brain around programming
90 patterns.
91 8sync uses some clever tricks involving "delimited continuations"
92 under the hood to make the code you write look familiar and
93 straightforward.
94 When you need to send a request to another actor and get some
95 information back from it without blocking, there's no need
96 to write a separate procedure@dots{} 8sync's scheduler will suspend
97 your procedure and wake it back up when a response is ready.
98 @item
99 Even nonblocking I/O code is straightforward to write.
100 Thanks to the "suspendable ports" code introduced in Guile 2.2,
101 writing asynchronous, nonblocking networked code looks mostly
102 like writing the same synchronous code.
103 8sync's scheduler handles suspending and resuming networked
104 code that would otherwise block.
105 @item
106 8sync aims to be "batteries included".
107 Useful subsystems for IRC bots, HTTP servers, and so on are
108 included out of the box.
109 @item
110 8sync prioritizes live hacking.
111 If using an editor like Emacs with a nice mode like Geiser,
112 an 8sync-using developer can change and fine-tune the behavior
113 of code @emph{while it runs}.
114 This makes both debugging and development much more natural,
115 allowing the right designs to evolve under your fingertips.
116 A productive hacker is a happy hacker, after all!
117 @end itemize
118
119 In the future, 8sync will also provide the ability to spawn and
120 communicate with actors on different threads, processes, and machines,
121 with most code running the same as if actors were running in the same
122 execution environment.
123
124 But as a caution, 8sync is still very young.
125 The API is stabilizing, but not yet stable, and it is not yet well
126 "battle-tested".
127 Hacker beware!
128 But, consider this as much an opportunity as a warning.
129 8sync is in a state where there is much room for feedback and
130 contributions.
131 Your help wanted!
132
133 And now, into the wild, beautiful frontier.
134 Onward!
135
136 @node Tutorial
137 @chapter Tutorial
138
139 @menu
140 * A silly little IRC bot::
141 * Writing our own actors::
142 * Writing our own network-enabled actor::
143 * An intermission on live hacking::
144 @end menu
145
146 \f
147
148 @node A silly little IRC bot
149 @section A silly little IRC bot
150
151 IRC!  Internet Relay Chat!
152 The classic chat protocol of the Internet.
153 And it turns out, one of the best places to learn about networked
154 programming.@footnote{In the 1990s I remember stumbling into some funky IRC chat rooms and
155 being astounded that people there had what they called "bots" hanging
156 around.
157 From then until now, I've always enjoyed encountering bots whose range
158 of functionality has spanned from saying absurd things, to taking
159 messages when their "owners" were offline, to reporting the weather,
160 to logging meetings for participants.
161 And it turns out, IRC bots are a great way to cut your teeth on
162 networked programming; since IRC is a fairly simple line-delineated
163 protocol, it's a great way to learn to interact with sockets.
164 (My first IRC bot helped my team pick a place to go to lunch, previously
165 a source of significant dispute!)
166 At the time of writing, venture capital awash startups are trying to
167 turn chatbots into "big business"@dots{} a strange (and perhaps absurd)
168 thing given chat bots being a fairly mundane novelty amongst hackers
169 and teenagers everywhere a few decades ago.}
170 We ourselves are going to explore chat bots as a basis for getting our
171 feet wet in 8sync.
172
173 First of all, we're going to need to import some modules.  Put this at
174 the top of your file:
175
176 @example
177 (use-modules (8sync)               ; 8sync's agenda and actors
178              (8sync systems irc)   ; the irc bot subsystem
179              (oop goops)           ; 8sync's actors use GOOPS
180              (ice-9 format)        ; basic string formatting
181              (ice-9 match))        ; pattern matching
182 @end example
183
184 Now we need to add our bot.  Initially, it won't do much.
185
186 @example
187 (define-class <my-irc-bot> (<irc-bot>))
188
189 (define-method (handle-line (irc-bot <my-irc-bot>) message
190                             speaker channel line emote?)
191   (if emote?
192       (format #t "~a emoted ~s in channel ~a\n"
193               speaker line channel)
194       (format #t "~a said ~s in channel ~a\n"
195               speaker line channel)))
196 @end example
197
198 We've just defined our own IRC bot!
199 This is an 8sync actor.
200 (8sync uses GOOPS to define actors.)
201 We extended the handle-line generic method, so this is the code that
202 will be called whenever the IRC bot "hears" anything.
203 This method is itself an action handler, hence the second argument
204 for @verb{~message~}, which we can ignore for now.
205 Pleasantly, the message's argument body is passed in as the rest of
206 the arguments.
207
208 For now the code is pretty basic: it just outputs whatever it "hears"
209 from a user in a channel to the current output port.
210 Pretty boring!
211 But it should help us make sure we have things working when we kick
212 things off.
213
214 Speaking of, even though we've defined our actor, it's not running
215 yet.  Time to fix that!
216
217 @example
218 (define* (run-bot #:key (username "examplebot")
219                   (server "irc.freenode.net")
220                   (channels '("##botchat")))
221   (define hive (make-hive))
222   (define irc-bot
223     (bootstrap-actor hive <my-irc-bot>
224                      #:username username
225                      #:server server
226                      #:channels channels))
227   (run-hive hive '()))
228 @end example
229
230 Actors are connected to something called a "hive", which is a
231 special kind of actor that runs and manages all the other actors.
232 Actors can spawn other actors, but before we start the hive we use
233 this special @verb{~bootstrap-actor~} method.
234 It takes the hive as its first argument, the actor class as the second
235 argument, and the rest are initialization arguments to the
236 actor.
237 @verb{~bootstrap-actor~} passes back not the actor itself (we don't
238 get access to that usually) but the @strong{id} of the actor.
239 (More on this later.)
240 Finally we run the hive with run-hive and pass it a list of
241 "bootstrapped" messages.
242 Normally actors send messages to each other (and sometimes themselves),
243 but we need to send a message or messages to start things or else
244 nothing is going to happen.
245
246 We can run it like:
247
248 @example
249 (run-bot #:username "some-bot-name") ; be creative!
250 @end example
251
252 Assuming all the tubes on the internet are properly connected, you
253 should be able to join the "##botchat" channel on irc.freenode.net and
254 see your bot join as well.
255 Now, as you probably guessed, you can't really @emph{do} much yet.
256 If you talk to the bot, it'll send messages to the terminal informing
257 you as such, but it's hardly a chat bot if it's not chatting yet.
258
259 So let's do the most boring (and annoying) thing possible.
260 Let's get it to echo whatever we say back to us.
261 Change handle-line to this:
262
263 @example
264 (define-method (handle-line (irc-bot <my-irc-bot>) message
265                             speaker channel line emote?)
266   (<- (actor-id irc-bot) 'send-line channel
267       (format #f "Bawwwwk! ~a says: ~a" speaker line)))
268 @end example
269
270 This will do exactly what it looks like: repeat back whatever anyone
271 says like an obnoxious parrot.
272 Give it a try, but don't keep it running for too long@dots{} this
273 bot is so annoying it's likely to get banned from whatever channel
274 you put it in.
275
276 This method handler does have the advantage of being simple though.
277 It introduces a new concept simply@dots{} sending a message!
278 Whenever you see "<-", you can think of that as saying "send this
279 message".
280 The arguments to "<-" are as follows: the actor sending the message,
281 the id of the actor the message is being sent to, the "action" we
282 want to invoke (a symbol), and the rest are arguments to the
283 "action handler" which is in this case send-line (with itself takes
284 two arguments: the channel our bot should send a message to, and
285 the line we want it to spit out to the channel).@footnote{8sync's name for sending a message, "<-", comes from older,
286 early lisp object oriented systems which were, as it turned out,
287 inspired by the actor model!
288 Eventually message passing was dropped in favor of something called
289 "generic functions" or "generic methods"
290 (you may observe we made use of such a thing in extending
291 handle-line).
292 Many lispers believe that there is no need for message passing
293 with generic methods and some advanced functional techniques,
294 but in a concurrent environment message passing becomes useful
295 again, especially when the communicating objects / actors are not
296 in the same address space.}
297
298 Normally in the actor model, we don't have direct references to
299 an actor, only an identifier.
300 This is for two reasons: to quasi-enforce the "shared nothing"
301 environment (actors absolutely control their own resources, and
302 "all you can do is send a message" to request that they modify
303 them) and because@dots{} well, you don't even know where that actor is!
304 Actors can be anything, and anywhere.
305 It's possible in 8sync to have an actor on a remote hive, which means
306 the actor could be on a remote process or even remote machine, and
307 in most cases message passing will look exactly the same.
308 (There are some exceptions; it's possible for two actors on the same
309 hive to "hand off" some special types of data that can't be serialized
310 across processes or the network, eg a socket or a closure, perhaps even
311 one with mutable state.
312 This must be done with care, and the actors should be careful both
313 to ensure that they are both local and that the actor handing things
314 off no longer accesses that value to preserve the actor model.
315 But this is an advanced topic, and we are getting ahead of ourselves.)
316 We have to supply the id of the receiving actor, and usually we'd have
317 only the identifier.
318 But since in this case, since the actor we're sending this to is
319 ourselves, we have to pass in our identifier, since the Hive won't
320 deliver to anything other than an address.
321
322 Astute readers may observe, since this is a case where we are just
323 referencing our own object, couldn't we just call "sending a line"
324 as a method of our own object without all the message passing?
325 Indeed, we do have such a method, so we @emph{could} rewrite handle-line
326 like so:
327
328 @example
329 (define-method (handle-line (irc-bot <my-irc-bot>) message
330                             speaker channel line emote?)
331   (irc-bot-send-line irc-bot channel
332                      (format #f "Bawwwwk! ~a says: ~a" speaker line)))
333 @end example
334
335 @dots{} but we want to get you comfortable and familiar with message
336 passing, and we'll be making use of this same message passing shortly
337 so that @emph{other} actors may participate in communicating with IRC
338 through our IRC bot.
339
340 Anyway, our current message handler is simply too annoying.
341 What we would really like to do is have our bot respond to individual
342 "commands" like this:
343
344 @example
345 <foo-user> examplebot: hi!
346 <examplebot> Oh hi foo-user!
347 <foo-user> examplebot: botsnack
348 <examplebot> Yippie! *does a dance!*
349 <foo-user> examplebot: echo I'm a very silly bot
350 <examplebot> I'm a very silly bot
351 @end example
352
353 Whee, that looks like fun!
354 To implement it, we're going to pull out Guile's pattern matcher.
355
356 @example
357 (define-method (handle-line (irc-bot <my-irc-bot>) message
358                             speaker channel line emote?)
359   (define my-name (irc-bot-username irc-bot))
360   (define (looks-like-me? str)
361     (or (equal? str my-name)
362         (equal? str (string-concatenate (list my-name ":")))))
363   (match (string-split line #\space)
364     (((? looks-like-me? _) action action-args ...)
365      (match action
366        ;; The classic botsnack!
367        ("botsnack"
368         (<- (actor-id irc-bot) 'send-line channel
369             "Yippie! *does a dance!*"))
370        ;; Return greeting
371        ((or "hello" "hello!" "hello." "greetings" "greetings." "greetings!"
372             "hei" "hei." "hei!" "hi" "hi!")
373         (<- (actor-id irc-bot) 'send-line channel
374             (format #f "Oh hi ~a!" speaker)))
375        ("echo"
376         (<- (actor-id irc-bot) 'send-line channel
377             (string-join action-args " ")))
378
379        ;; --->  Add yours here <---
380
381        ;; Default
382        (_
383         (<- (actor-id irc-bot) 'send-line channel
384             "*stupid puppy look*"))))))
385 @end example
386
387 Parsing the pattern matcher syntax is left as an exercise for the
388 reader.
389
390 If you're getting the sense that we could make this a bit less wordy,
391 you're right:
392
393 @example
394 (define-method (handle-line (irc-bot <my-irc-bot>) message
395                             speaker channel line emote?)
396   (define my-name (irc-bot-username irc-bot))
397   (define (looks-like-me? str)
398     (or (equal? str my-name)
399         (equal? str (string-concatenate (list my-name ":")))))
400   (define (respond respond-line)
401     (<- (actor-id irc-bot) 'send-line channel
402         respond-line))
403   (match (string-split line #\space)
404     (((? looks-like-me? _) action action-args ...)
405      (match action
406        ;; The classic botsnack!
407        ("botsnack"
408         (respond "Yippie! *does a dance!*"))
409        ;; Return greeting
410        ((or "hello" "hello!" "hello." "greetings" "greetings." "greetings!"
411             "hei" "hei." "hei!" "hi" "hi." "hi!")
412         (respond (format #f "Oh hi ~a!" speaker)))
413        ("echo"
414         (respond (string-join action-args " ")))
415
416        ;; --->  Add yours here <---
417
418        ;; Default
419        (_
420         (respond "*stupid puppy look*"))))))
421 @end example
422
423 Okay, that looks pretty good!
424 Now we have enough information to build an IRC bot that can do a lot
425 of things.
426 Take some time to experiment with extending the bot a bit before
427 moving on to the next section!
428 What cool commands can you add?
429
430 \f
431 @node Writing our own actors
432 @section Writing our own actors
433
434 Let's write the most basic, boring actor possible.
435 How about an actor that start sleeping, and keeps sleeping?
436
437 @example
438 (use-modules (oop goops)
439              (8sync))
440
441 (define-class <sleeper> (<actor>)
442   (actions #:allocation #:each-subclass
443            #:init-thunk (build-actions
444                          (*init* sleeper-loop)))
445   (sleep-secs #:init-value 1 #:getter sleeper-sleep-secs))
446
447 (define (sleeper-loop actor message)
448   (while (actor-alive? actor)
449     (display "Zzzzzzzz....\n")
450     ;; Sleep for one second
451     (8sleep (sleeper-sleep-secs actor))))
452
453 (let* ((hive (make-hive))
454        (sleeper (bootstrap-actor hive <sleeper>)))
455   (run-hive hive '()))
456 @end example
457
458 We see some particular things in this example.
459 One thing is that our @verb{~<sleeper>~} actor has an actions slot.
460 This is used to look up what the "action handler" for a message is.
461 We have to set the #:allocation to either @verb{~#:each-subclass~}
462 and use @verb{~#:init-thunk~}.@footnote{@verb{~build-subclass~} returns
463 a thunk to be called later so that each subclass may correctly build
464 its own instance.  This is important because the structure returned
465 contains a cache, which may vary from subclass to subclass based on
466 its inheritance structure.}
467
468 The only action handler we've added is for @verb{~*init*~}, which is called
469 implicitly when the actor first starts up.
470 (This will be true whether we bootstrap the actor before the hive
471 starts or create it during the hive's execution.)
472
473 In our sleeper-loop we also see a call to "8sleep".
474 "8sleep" is like Guile's "sleep" method, except it is non-blocking
475 and will always yield to the scheduler.
476
477 Our while loop also checks "actor-alive?" to see whether or not
478 it is still registered.
479 In general, if you keep a loop in your actor that regularly yields
480 to the scheduler, you should check this.@footnote{Or rather, for now you should call @verb{~actor-alive?~} if your code
481 is looping like this.
482 In the future, after an actor dies, its coroutines will
483 automatically be "canceled".}
484 (An alternate way to handle it would be to not use a while loop at all
485 but simply send a message to ourselves with "<-" to call the
486 sleeper-loop handler again.
487 If the actor was dead, the message simply would not be delivered and
488 thus the loop would stop.)
489
490 It turns out we could have written the class for the actor much more
491 simply:
492
493 @example
494 ;; You could do this instead of the define-class above.
495 (define-actor <sleeper> (<actor>)
496   ((*init* sleeper-loop)))
497 @end example
498
499 This is sugar, and expands into exactly the same thing as the
500 define-class above.
501 The third argument is an argument list, the same as what's passed
502 into build-actions.
503 Everything after that is a slot.
504 So for example, if we had added an optional slot to specify
505 how many seconds to sleep, we could have done it like so:
506
507 @example
508 (define-actor <sleeper> (<actor>)
509   ((*init* sleeper-loop))
510   (sleep-secs #:init-value 1
511               #:getter sleeper-sleep-secs))
512 @end example
513
514 This actor is pretty lazy though.
515 Time to get back to work!
516 Let's build a worker / manager type system.
517
518 @example
519 (use-modules (8sync)
520              (oop goops))
521
522 (define-actor <manager> (<actor>)
523   ((assign-task manager-assign-task))
524   (direct-report #:init-keyword #:direct-report
525                  #:getter manager-direct-report))
526
527 (define (manager-assign-task manager message difficulty)
528   "Delegate a task to our direct report"
529   (display "manager> Work on this task for me!\n")
530   (<- (manager-direct-report manager)
531       'work-on-this difficulty))
532 @end example
533
534 This manager keeps track of a direct report and tells them to start
535 working on a task@dots{} simple delegation.
536 Nothing here is really new, but note that our friend "<-" (which means
537 "send message") is back.
538 There's one difference this time@dots{} the first time we saw "<-" was in
539 the handle-line procedure of the irc-bot, and in that case we explicitly
540 pulled the actor-id after the actor we were sending the message to
541 (ourselves), which we aren't doing here.
542 But that was an unusual case, because the actor was ourself.
543 In this case, and in general, actors don't have direct references to
544 other actors; instead, all they have is access to identifiers which
545 reference other actors.
546
547 @example
548 (define-actor <worker> (<actor>)
549   ((work-on-this worker-work-on-this))
550   (task-left #:init-keyword #:task-left
551              #:accessor worker-task-left))
552
553 (define (worker-work-on-this worker message difficulty)
554   "Work on one task until done."
555   (set! (worker-task-left worker) difficulty)
556   (display "worker> Whatever you say, boss!\n")
557   (while (and (actor-alive? worker)
558               (> (worker-task-left worker) 0))
559     (display "worker> *huff puff*\n")
560     (set! (worker-task-left worker)
561           (- (worker-task-left worker) 1))
562     (8sleep (/ 1 3))))
563 @end example
564
565 The worker also contains familiar code, but we now see that we can
566 call 8sleep with non-integer real numbers.
567
568 Looks like there's nothing left to do but run it.
569
570 @example
571 (let* ((hive (make-hive))
572        (worker (bootstrap-actor hive <worker>))
573        (manager (bootstrap-actor hive <manager>
574                                  #:direct-report worker)))
575   (run-hive hive (list (bootstrap-message hive manager 'assign-task 5))))
576 @end example
577
578 Unlike the @verb{~<sleeper>~}, our @verb{~<manager>~} doesn't have an implicit
579 @verb{~*init*~} method, so we've bootstrapped the calling @verb{~assign-task~} action.
580
581 @example
582 manager> Work on this task for me!
583 worker> Whatever you say, boss!
584 worker> *huff puff*
585 worker> *huff puff*
586 worker> *huff puff*
587 worker> *huff puff*
588 worker> *huff puff*
589 @end example
590
591 "<-" pays no attention to what happens with the messages it has sent
592 off.
593 This is useful in many cases@dots{} we can blast off many messages and
594 continue along without holding anything back.
595
596 But sometimes we want to make sure that something completes before
597 we do something else, or we want to send a message and get some sort
598 of information back.
599 Luckily 8sync comes with an answer to that with "<-wait", which will
600 suspend the caller until the callee gives some sort of response, but
601 which does not block the rest of the program from running.
602 Let's try applying that to our own code by turning our manager
603 into a micromanager.
604
605 @example
606 ;;; Update this method
607 (define (manager-assign-task manager message difficulty)
608   "Delegate a task to our direct report"
609   (display "manager> Work on this task for me!\n")
610   (<- (manager-direct-report manager)
611       'work-on-this difficulty)
612
613   ;; Wait a moment, then call the micromanagement loop
614   (8sleep (/ 1 2))
615   (manager-micromanage-loop manager))
616
617 ;;; And add the following
618 ;;;   (... Note: do not model actual employee management off this)
619 (define (manager-micromanage-loop manager)
620   "Pester direct report until they're done with their task."
621   (display "manager> Are you done yet???\n")
622   (let ((worker-is-done
623          (mbody-val (<-wait (manager-direct-report manager)
624                             'done-yet?))))
625     (if worker-is-done
626         (begin (display "manager> Oh!  I guess you can go home then.\n")
627                (<- (manager-direct-report manager) 'go-home))
628         (begin (display "manager> Harumph!\n")
629                (8sleep (/ 1 2))
630                (when (actor-alive? manager)
631                  (manager-micromanage-loop manager))))))
632 @end example
633
634 We've appended a micromanagement loop here@dots{} but what's going on?
635 "<-wait", as it sounds, waits for a reply, and returns a reply
636 message.
637 In this case there's a value in the body of the message we want,
638 so we pull it out with mbody-val.
639 (It's possible for a remote actor to return multiple values, in which
640 case we'd want to use mbody-receive, but that's a bit more
641 complicated.)
642
643 Of course, we need to update our worker accordingly as well.
644
645 @example
646 ;;; Update the worker to add the following new actions:
647 (define-actor <worker> (<actor>)
648   ((work-on-this worker-work-on-this)
649    ;; Add these:
650    (done-yet? worker-done-yet?)
651    (go-home worker-go-home))
652   (task-left #:init-keyword #:task-left
653              #:accessor worker-task-left))
654
655 ;;; New procedures:
656 (define (worker-done-yet? worker message)
657   "Reply with whether or not we're done yet."
658   (let ((am-i-done? (= (worker-task-left worker) 0)))
659     (if am-i-done?
660         (display "worker> Yes, I finished up!\n")
661         (display "worker> No... I'm still working on it...\n"))
662     (<-reply message am-i-done?)))
663
664 (define (worker-go-home worker message)
665   "It's off of work for us!"
666   (display "worker> Whew!  Free at last.\n")
667   (self-destruct worker))
668 @end example
669
670 (As you've probably guessed, you wouldn't normally call @verb{~display~}
671 everywhere as we are in this program@dots{} that's just to make the
672 examples more illustrative.)
673
674 "<-reply" is what actually returns the information to the actor
675 waiting on the reply.
676 It takes as an argument the actor sending the message, the message
677 it is in reply to, and the rest of the arguments are the "body" of
678 the message.
679 (If an actor handles a message that is being "waited on" but does not
680 explicitly reply to it, an auto-reply with an empty body will be
681 triggered so that the waiting actor is not left waiting around.)
682
683 The last thing to note is the call to "self-destruct".
684 This does what you might expect: it removes the actor from the hive.
685 No new messages will be sent to it.
686 Ka-poof!
687
688 Running it is the same as before:
689
690 @example
691 (let* ((hive (make-hive))
692        (worker (bootstrap-actor hive <worker>))
693        (manager (bootstrap-actor hive <manager>
694                                  #:direct-report worker)))
695   (run-hive hive (list (bootstrap-message hive manager 'assign-task 5))))
696 @end example
697
698 But the output is a bit different:
699
700 @example
701 manager> Work on this task for me!
702 worker> Whatever you say, boss!
703 worker> *huff puff*
704 worker> *huff puff*
705 manager> Are you done yet???
706 worker> No... I'm still working on it...
707 manager> Harumph!
708 worker> *huff puff*
709 manager> Are you done yet???
710 worker> *huff puff*
711 worker> No... I'm still working on it...
712 manager> Harumph!
713 worker> *huff puff*
714 manager> Are you done yet???
715 worker> Yes, I finished up!
716 manager> Oh!  I guess you can go home then.
717 worker> Whew!  Free at last.
718 @end example
719
720 \f
721 @node Writing our own network-enabled actor
722 @section Writing our own network-enabled actor
723
724 So, you want to write a networked actor!
725 Well, luckily that's pretty easy, especially with all you know so far.
726
727 @example
728 (use-modules (oop goops)
729              (8sync)
730              (ice-9 rdelim)  ; line delineated i/o
731              (ice-9 match))  ; pattern matching
732
733 (define-actor <telcmd> (<actor>)
734   ((*init* telcmd-init)
735    (*cleanup* telcmd-cleanup)
736    (new-client telcmd-new-client)
737    (handle-line telcmd-handle-line))
738   (socket #:accessor telcmd-socket
739           #:init-value #f))
740 @end example
741
742 Nothing surprising about the actor definition, though we do see that
743 it has a slot for a socket.
744 Unsurprisingly, that will be set up in the @verb{~*init*~} handler.
745
746 @example
747 (define (set-port-nonblocking! port)
748   (let ((flags (fcntl port F_GETFL)))
749     (fcntl port F_SETFL (logior O_NONBLOCK flags))))
750
751 (define (setup-socket)
752   ;; our socket
753   (define s
754     (socket PF_INET SOCK_STREAM 0))
755   ;; reuse port even if busy
756   (setsockopt s SOL_SOCKET SO_REUSEADDR 1)
757   ;; connect to port 8889 on localhost
758   (bind s AF_INET INADDR_LOOPBACK 8889)
759   ;; make it nonblocking and start listening
760   (set-port-nonblocking! s)
761   (listen s 5)
762   s)
763
764 (define (telcmd-init telcmd message)
765   (set! (telcmd-socket telcmd) (setup-socket))
766   (display "Connect like: telnet localhost 8889\n")
767   (while (actor-alive? telcmd)
768     (let ((client-connection (accept (telcmd-socket telcmd))))
769       (<- (actor-id telcmd) 'new-client client-connection))))
770
771 (define (telcmd-cleanup telcmd message)
772   (display "Closing socket!\n")
773   (when (telcmd-socket telcmd)
774     (close (telcmd-socket telcmd))))
775 @end example
776
777 That @verb{~setup-socket~} code looks pretty hard to read!
778 But that's pretty standard code for setting up a socket.
779 One special thing is done though@dots{} the call to
780 @verb{~set-port-nonblocking!~} sets flags on the socket port so that,
781 you guessed it, will be a nonblocking port.
782
783 This is put to immediate use in the telcmd-init method.
784 This code looks suspiciously like it @emph{should} block@dots{} after
785 all, it just keeps looping forever.
786 But since 8sync is using Guile's suspendable ports code feature,
787 so every time this loop hits the @verb{~accept~} call, if that call
788 @emph{would have} blocked, instead this whole procedure suspends
789 to the scheduler@dots{} automatically!@dots{} allowing other code to run.
790
791 So, as soon as we do accept a connection, we send a message to
792 ourselves with the @verb{~new-client~} action.
793 But wait!
794 Aren't actors only supposed to handle one message at a time?
795 If the telcmd-init loop just keeps on looping and looping,
796 when will the @verb{~new-client~} message ever be handled?
797 8sync actors only receive one message at a time, but by default if an
798 actor's message handler suspends to the agenda for some reason (such
799 as to send a message or on handling I/O), that actor may continue to
800 accept other messages, but always in the same thread.@footnote{This is customizable: an actor can be set up to queue messages so
801 that absolutely no messages are handled until the actor completely
802 finishes handling one message.
803 Our loop couldn't look quite like this though!}
804
805 We also see that we've established a @verb{~*cleanup*~} handler.
806 This is run any time either the actor dies, either through self
807 destructing, because the hive completes its work, or because
808 a signal was sent to interrupt or terminate our program.
809 In our case, we politely close the socket when @verb{~<telcmd>~} dies.
810
811 @example
812 (define (telcmd-new-client telcmd message client-connection)
813   (define client (car client-connection))
814   (set-port-nonblocking! client)
815   (let loop ()
816     (let ((line (read-line client)))
817       (cond ((eof-object? line)
818              (close client))
819             (else
820              (<- (actor-id telcmd) 'handle-line
821                  client (string-trim-right line #\return))
822              (when (actor-alive? telcmd)
823                (loop)))))))
824
825 (define (telcmd-handle-line telcmd message client line)
826   (match (string-split line #\space)
827     (("") #f)  ; ignore empty lines
828     (("time" _ ...)
829      (display
830       (strftime "The time is: %c\n" (localtime (current-time)))
831       client))
832     (("echo" rest ...)
833      (format client "~a\n" (string-join rest " ")))
834     ;; default
835     (_ (display "Sorry, I don't know that command.\n" client))))
836 @end example
837
838 Okay, we have a client, so we handle it!
839 And once again@dots{} we see this goes off on a loop of its own!
840 (Also once again, we have to do the @verb{~set-port-nonblocking!~} song and
841 dance.)
842 This loop also automatically suspends when it would otherwise block@dots{}
843 as long as read-line has information to process, it'll keep going, but
844 if it would have blocked waiting for input, then it would suspend the
845 agenda.@footnote{If there's a lot of data coming in and you don't want your I/O loop
846 to become too "greedy", take a look at @verb{~setvbuf~}.}
847
848 The actual method called whenever we have a "line" of input is pretty
849 straightforward@dots{} in fact it looks an awful lot like the IRC bot
850 handle-line procedure we used earlier.
851 No surprises there!@footnote{Well, there may be one surprise to a careful observer.
852 Why are we sending a message to ourselves?
853 Couldn't we have just dropped the argument of "message" to
854 telcmd-handle-line and just called it like any other procedure?
855 Indeed, we @emph{could} do that, but sending a message to ourself has
856 an added advantage: if we accidentally "break" the
857 telcmd-handle-line procedure in some way (say we add a fun new
858 command we're playing with it), raising an exception won't break
859 and disconnect the client's main loop, it'll just break the
860 message handler for that one line, and our telcmd will happily
861 chug along accepting another command from the user while we try
862 to figure out what happened to the last one.}
863
864 Now let's run it:
865
866 @example
867 (let* ((hive (make-hive))
868        (telcmd (bootstrap-actor hive <telcmd>)))
869   (run-hive hive '()))
870 @end example
871
872 Open up another terminal@dots{} you can connect via telnet:
873
874 @example
875 $ telnet localhost 8889
876 Trying 127.0.0.1...
877 Connected to localhost.
878 Escape character is '^]'.
879 time
880 The time is: Thu Jan  5 03:20:17 2017
881 echo this is an echo
882 this is an echo
883 shmmmmmmorp
884 Sorry, I don't know that command.
885 @end example
886
887 Horray, it works!
888 Type @verb{~Ctrl+] Ctrl+d~} to exit telnet.
889
890 Not so bad!
891 There's more that could be optimized, but we'll consider that to be
892 advanced topics of discussion.
893
894 So that's a pretty solid intro to how 8sync works!
895 Now that you've gone through this introduction, we hope you'll have fun
896 writing and hooking together your own actors.
897 Since actors are so modular, it's easy to have a program that has
898 multiple subystems working together.
899 You could build a worker queue system that displayed a web interface
900 and spat out notifications about when tasks finish to IRC, and making
901 all those actors talk to each other should be a piece of cake.
902 The sky's the limit!
903
904 Happy hacking!
905
906 \f
907 @node An intermission on live hacking
908 @section An intermission on live hacking
909
910 This section is optional, but highly recommended.
911 It requires that you're a user of GNU Emacs.
912 If you aren't, don't worry@dots{} you can forge ahead and come back in case
913 you ever do become an Emacs user.
914 (If you're more familiar with Vi/Vim style editing, I hear good things
915 about Spacemacs@dots{})
916
917 Remember all the way back when we were working on the IRC bot?
918 So you may have noticed while updating that section that the
919 start/stop cycle of hacking isn't really ideal.
920 You might either edit a file in your editor, then run it, or
921 type the whole program into the REPL, but then you'll have to spend
922 extra time copying it to a file.
923 Wouldn't it be nice if it were possible to both write code in a
924 file and try it as you go?
925 And wouldn't it be even better if you could live edit a program
926 while it's running?
927
928 Luckily, there's a great Emacs mode called Geiser which makes
929 editing and hacking and experimenting all happen in harmony.
930 And even better, 8sync is optimized for this experience.
931 8sync provides easy drop-in "cooperative REPL" support, and
932 most code can be simply redefined on the fly in 8sync through Geiser
933 and actors will immediately update their behavior, so you can test
934 and tweak things as you go.
935
936 Okay, enough talking.  Let's add it!
937 Redefine run-bot like so:
938
939 @example
940 (define* (run-bot #:key (username "examplebot")
941                   (server "irc.freenode.net")
942                   (channels '("##botchat"))
943                   (repl-path "/tmp/8sync-repl"))
944   (define hive (make-hive))
945   (define irc-bot
946     (bootstrap-actor hive <my-irc-bot>
947                      #:username username
948                      #:server server
949                      #:channels channels))
950   (define repl-manager
951     (bootstrap-actor hive <repl-manager>
952                      #:path repl-path))
953
954   (run-hive hive '()))
955 @end example
956
957 If we put a call to run-bot at the bottom of our file we can call it,
958 and the repl-manager will start something we can connect to automatically.
959 Horray!
960 Now when we run this it'll start up a REPL with a unix domain socket at
961 the repl-path.
962 We can connect to it in emacs like so:
963
964 @example
965 M-x geiser-connect-local <RET> guile <RET> /tmp/8sync-repl <RET>
966
967 @end example
968
969 Okay, so what does this get us?
970 Well, we can now live edit our program.
971 Let's change how our bot behaves a bit.
972 Let's change handle-line and tweak how the bot responds to a botsnack.
973 Change this part:
974
975 @example
976 ;; From this:
977 ("botsnack"
978  (respond "Yippie! *does a dance!*"))
979
980 ;; To this:
981 ("botsnack"
982  (respond "Yippie! *catches botsnack in midair!*"))
983 @end example
984
985 Okay, now let's evaluate the change of the definition.
986 You can hit "C-M-x" anywhere in the definition to re-evaluate.
987 (You can also position your cursor at the end of the definition and press
988 "C-x C-e", but I've come to like "C-M-x" better because I can evaluate as soon
989 as I'm done writing.)
990 Now, on IRC, ask your bot for a botsnack.
991 The bot should give the new message@dots{} with no need to stop and start the
992 program!
993
994 Let's fix a bug live.
995 Our current program works great if you talk to your bot in the same
996 IRC channel, but what if you try to talk to them over private message?
997
998 @example
999 IRC> /query examplebot
1000 <foo-user> examplebot: hi!
1001 @end example
1002
1003 Hm, we aren't seeing any response on IRC!
1004 Huh?  What's going on?
1005 It's time to do some debugging.
1006 There are plenty of debugging tools in Guile, but sometimes the simplest
1007 is the nicest, and the simplest debugging route around is good old
1008 fashioned print debugging.
1009
1010 It turns out Guile has an under-advertised feature which makes print
1011 debugging really easy called "pk", pronounced "peek".
1012 What pk accepts a list of arguments, prints out the whole thing,
1013 but returns the last argument.
1014 This makes wrapping bits of our code pretty easy to see what's
1015 going on.
1016 So let's peek into our program with pk.
1017 Edit the respond section to see what channel it's really sending
1018 things to:
1019
1020 @example
1021 (define-method (handle-line (irc-bot <my-irc-bot>) message
1022                             speaker channel line emote?)
1023   ;; [... snip ...]
1024   (define (respond respond-line)
1025     (<- (actor-id irc-bot) 'send-line (pk 'channel channel)
1026         respond-line))
1027   ;; [... snip ...]
1028   )
1029 @end example
1030
1031 Re-evaluate.
1032 Now let's ping our bot in both the channel and over PM.
1033
1034 @example
1035 ;;; (channel "##botchat")
1036
1037 ;;; (channel "sinkbot")
1038 @end example
1039
1040 Oh okay, this makes sense.
1041 When we're talking in a normal multi-user channel, the channel we see
1042 the message coming from is the same one we send to.
1043 But over PM, the channel is a username, and in this case the username
1044 we're sending our line of text to is ourselves.
1045 That isn't what we want.
1046 Let's edit our code so that if we see that the channel we're sending
1047 to looks like our own username that we respond back to the sender.
1048 (We can remove the pk now that we know what's going on.)
1049
1050 @example
1051 (define-method (handle-line (irc-bot <my-irc-bot>) message
1052                             speaker channel line emote?)
1053   ;; [... snip ...]
1054   (define (respond respond-line)
1055     (<- (actor-id irc-bot) 'send-line
1056         (if (looks-like-me? channel)
1057             speaker    ; PM session
1058             channel)   ; normal IRC channel
1059         respond-line))
1060   ;; [... snip ...]
1061   )
1062 @end example
1063
1064 Re-evaluate and test.
1065
1066 @example
1067 IRC> /query examplebot
1068 <foo-user> examplebot: hi!
1069 <examplebot> Oh hi foo-user!
1070 @end example
1071
1072 Horray!
1073
1074 \f
1075 @node API reference
1076 @chapter API reference
1077
1078 \f
1079 @node Systems reference
1080 @chapter Systems reference
1081
1082 @menu
1083 * IRC::
1084 * Web / HTTP::
1085 @end menu
1086
1087 \f
1088 @node IRC
1089 @section IRC
1090
1091 \f
1092 @node Web / HTTP
1093 @section Web / HTTP
1094
1095 \f
1096 @node Addendum
1097 @chapter Addendum
1098
1099 @menu
1100 * Recommended emacs additions::
1101 * 8sync and Fibers::
1102 * 8sync's license and general comments on copyleft::
1103 * Acknowledgements::
1104 @end menu
1105
1106 \f
1107 @node Recommended emacs additions
1108 @section Recommended emacs additions
1109
1110 In order for @verb{~mbody-receive~} to indent properly, put this in your
1111 .emacs:
1112
1113 @lisp
1114 (put 'mbody-receive 'scheme-indent-function 2)
1115 @end lisp
1116
1117 @node 8sync and Fibers
1118 @section 8sync and Fibers
1119
1120 One other major library for asynchronous communication in Guile-land
1121 is @uref{https://github.com/wingo/fibers/,Fibers}.
1122 There's a lot of overlap:
1123
1124 @itemize
1125 @item
1126 Both use Guile's suspendable-ports facility
1127 @item
1128 Both communicate between asynchronous processes using message passing;
1129 you don't have to squint hard to see the relationship between Fibers'
1130 channels and 8sync's actor inboxes.
1131 @end itemize
1132
1133 However, there are clearly differences too.
1134 There's a one to one relationship between 8sync actors and an actor inbox,
1135 whereas each Fibers fiber may read from multiple channels, for example.
1136
1137 Luckily, it turns out there's a clear relationship, based on real,
1138 actual theory!
1139 8sync is based on the @uref{https://en.wikipedia.org/wiki/Actor_model,actor model} whereas fibers follows
1140 @uref{http://usingcsp.com/,Communicating Sequential Processes (CSP)}, which is a form of
1141 @uref{https://en.wikipedia.org/wiki/Process_calculus,process calculi}.
1142 And it turns out, the
1143 @uref{https://en.wikipedia.org/wiki/Actor_model_and_process_calculi,relationship between the actor model and process calculi} is well documented,
1144 and even more precisely, the
1145 @uref{https://en.wikipedia.org/wiki/Communicating_sequential_processes#Comparison_with_the_Actor_Model,relationship between CSP and the actor model} is well understood too.
1146
1147 So, 8sync and Fibers do take somewhat different approaches, but both
1148 have a solid theoretical backing@dots{} and their theories are well
1149 understood in terms of each other.
1150 Good news for theory nerds!
1151
1152 (Since the actors and CSP are @uref{https://en.wikipedia.org/wiki/Dual_%28mathematics%29,dual}, maybe eventually 8sync will be
1153 implemented on top of Fibers@dots{} that remains to be seen!)
1154
1155 \f
1156 @node 8sync's license and general comments on copyleft
1157 @section 8sync's license and general comments on copyleft
1158
1159 8sync is released under the GNU LGPL (Lesser General Public License),
1160 version 3 or later, as published by the Free Software Foundation.
1161 The short version of this is that if you distribute a modifications to
1162 8sync, whether alone or in some larger combination, must release the
1163 corresponding source code.
1164 A program which uses this library, if distributed without source code,
1165 must also allow relinking with a modified version of this library.
1166 In general, it is best to contribute them back to 8sync under the same terms;
1167 we'd appreciate any enhancements or fixes to be contributed upstream to
1168 8sync itself.
1169 (This is an intentional oversimplification for brevity, please read the LGPL
1170 for the precise terms.)
1171
1172 This usage of the LGPL helps us ensure that 8sync and derivatives of
1173 8sync as a library will remain free.
1174 Though it is not a requirement, we request you use 8sync to build free
1175 software rather than use it to contribute to the growing world of
1176 proprietary software.
1177
1178 The choice of the LGPL for 8sync was a strategic one.
1179 This is not a general recommendation to use the LGPL instead of the GPL
1180 for all libraries.
1181 In general, we encourage stronger copyleft.
1182 (For more thinking on this position, see
1183 @uref{https://www.gnu.org/licenses/why-not-lgpl.html,
1184       Why you shouldn't use the Lesser GPL for your next library}.)
1185
1186 Although 8sync provides some unique features, its main functionality
1187 is as an asynchronous programming environment, and there are many
1188 other asynchronous programming environments out there such as Node.js
1189 for Javascript and Asyncio for Python (there are others as well).
1190 It is popular in some of these communities to hold anti-copyleft positions,
1191 which is unfortunate, and many community members seem to be adopting
1192 these positions because other developers they look up to are holding
1193 them.
1194 If you have come from one of these communities and are exploring 8sync, we
1195 hope reading this will help you reconsider your position.
1196
1197 In particular, if you are building a library or application that uses
1198 8sync in some useful way, consider releasing your program under the GNU
1199 GPL or GNU AGPL!
1200 In a world where more and more software is locked down, where software is used
1201 to restrict users, we could use every chance we can get to provide
1202 protections so that software which is free remains free, and encourages even
1203 more software freedom to be built upon it.
1204
1205 So to answer the question, ``Can I build a proprietary program on top of
1206 8sync?'' our response is
1207 ``Yes, but please don't.
1208 Choose to release your software under a freedom-respecting license.
1209 And help us turn the tide towards greater software freedom...
1210 consider a strong copyleft license!''
1211
1212 @node Acknowledgements
1213 @section Acknowledgements
1214
1215 8sync has a number of inspirations:
1216
1217 @itemize @bullet
1218 @item
1219 @uref{https://docs.python.org/3.5/library/asyncio.html, asyncio}
1220 for Python provides a nice asynchronous programming environment, and
1221 makes great use of generator-style coroutines.
1222 It's a bit more difficult to work with than 8sync (or so thinks the author)
1223 because you have to ``line up'' the coroutines.
1224
1225 @item
1226 @uref{http://dthompson.us/pages/software/sly.html, Sly}
1227 by David Thompson is an awesome functional reactive game programming
1228 library for Guile.
1229 If you want to write graphical games, Sly is almost certainly a better choice
1230 than 8sync.
1231 Thanks to David for being very patient in explaining tough concepts;
1232 experience on hacking Sly greatly informed 8sync's development.
1233 (Check out Sly, it rocks!)
1234
1235 @item
1236 Reading @uref{https://mitpress.mit.edu/sicp/, SICP}, particularly
1237 @uref{https://mitpress.mit.edu/sicp/full-text/book/book-Z-H-19.html#%_chap_3,
1238       Chapter 3's writings on concurrent systems},
1239 greatly informed 8sync's design.
1240
1241 @item
1242 Finally, @uref{http://xudd.readthedocs.io/en/latest/, XUDD}
1243 was an earlier ``research project'' that preceeded 8sync.
1244 It attempted to bring an actor model system to Python.
1245 However, the author eventually grew frustrated with some of Python's
1246 limitations, fell in love with Guile, and well... now we have 8sync.
1247 Much of 8sync's actor model design came from experiments in developing
1248 XUDD.
1249
1250 @end itemize
1251
1252 The motivation to build 8sync came out of
1253 @uref{https://lists.gnu.org/archive/html/guile-devel/2015-10/msg00015.html,
1254       a conversation}
1255 at the FSF 30th party between Mark Weaver, David Thompson, Andrew
1256 Engelbrecht, and Christopher Allan Webber over how to build
1257 an asynchronous event loop for Guile and just what would be needed.
1258
1259 A little over a month after that, hacking on 8sync began!
1260
1261 \f
1262
1263 @node Copying This Manual
1264 @appendix Copying This Manual
1265
1266 This manual is licensed under the GNU Free Documentation License, with
1267 no invariant sections.  At your option, it is also available under the
1268 GNU Lesser General Public License, as published by the Free Software
1269 Foundation, version 3 or any later version.
1270
1271 \f
1272
1273 @menu
1274 * GNU Free Documentation License::  License for copying this manual.
1275 @end menu
1276
1277 @c Get fdl.texi from http://www.gnu.org/licenses/fdl.html
1278 @node GNU Free Documentation License
1279 @section GNU Free Documentation License
1280 @include fdl.texi
1281
1282 @node Index
1283 @unnumbered Index
1284
1285 @syncodeindex tp fn
1286 @syncodeindex vr fn
1287 @printindex fn
1288
1289 @bye
1290
1291 @c 8sync.texi ends here