doc: Delete trailing whitespace.
[8sync.git] / doc / 8sync-new-manual.org
index 3c81bc8499d9bb665d73ba2db8276a28866a77c2..e15c50ba3d41224102ec0812ae0fca4b023eb2e6 100644 (file)
@@ -4,14 +4,14 @@
 # with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
 # A copy of the license is included in the section entitled ``GNU
 # Free Documentation License''.
-# 
+#
 # A copy of the license is also available from the Free Software
 # Foundation Web site at http://www.gnu.org/licenses/fdl.html
-# 
-# Altenately, this document is also available under the Lesser General
+#
+# Alternately, this document is also available under the Lesser General
 # Public License, version 3 or later, as published by the Free Software
 # Foundation.
-# 
+#
 # A copy of the license is also available from the Free Software
 # Foundation Web site at http://www.gnu.org/licenses/lgpl.html
 
@@ -103,8 +103,8 @@ Now we need to add our bot.  Initially, it won't do much.
 #+BEGIN_SRC scheme
   (define-class <my-irc-bot> (<irc-bot>))
 
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     (if emote?
         (format #t "~a emoted ~s in channel ~a\n"
                 speaker line channel)
@@ -117,6 +117,11 @@ This is an 8sync actor.
 (8sync uses GOOPS to define actors.)
 We extended the handle-line generic method, so this is the code that
 will be called whenever the IRC bot "hears" anything.
+This method is itself an action handler, hence the second argument
+for =message=, which we can ignore for now.
+Pleasantly, the message's argument body is passed in as the rest of
+the arguments.
+
 For now the code is pretty basic: it just outputs whatever it "hears"
 from a user in a channel to the current output port.
 Pretty boring!
@@ -132,22 +137,21 @@ yet.  Time to fix that!
                   (channels '("##botchat")))
   (define hive (make-hive))
   (define irc-bot
-    (bootstrap-actor* hive <my-irc-bot> "irc-bot"
-                      #:username username
-                      #:server server
-                      #:channels channels))
+    (bootstrap-actor hive <my-irc-bot>
+                     #:username username
+                     #:server server
+                     #:channels channels))
   (run-hive hive '()))
 #+END_SRC
 
 Actors are connected to something called a "hive", which is a
 special kind of actor that runs and manages all the other actors.
 Actors can spawn other actors, but before we start the hive we use
-this special "bootstrap-actor*" method.
+this special =bootstrap-actor= method.
 It takes the hive as its first argument, the actor class as the second
-argument, a decorative "cookie" as the third argument (this is
-optional, but it helps with debugging... you can skip it by setting it
-to #f if you prefer), and the rest are initialization arguments to the
-actor.  bootstrap-actor* passes back not the actor itself (we don't
+argument, and the rest are initialization arguments to the
+actor.
+=bootstrap-actor= passes back not the actor itself (we don't
 get access to that usually) but the *id* of the actor.
 (More on this later.)
 Finally we run the hive with run-hive and pass it a list of
@@ -174,8 +178,8 @@ Let's get it to echo whatever we say back to us.
 Change handle-line to this:
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     (<- (actor-id irc-bot) 'send-line channel
         (format #f "Bawwwwk! ~a says: ~a" speaker line)))
 #+END_SRC
@@ -195,20 +199,7 @@ the id of the actor the message is being sent to, the "action" we
 want to invoke (a symbol), and the rest are arguments to the
 "action handler" which is in this case send-line (with itself takes
 two arguments: the channel our bot should send a message to, and
-the line we want it to spit out to the channel).
-
-(Footnote: 8sync's name for sending a message, "<-", comes from older,
-early lisp object oriented systems which were, as it turned out,
-inspired by the actor model!
-Eventually message passing was dropped in favor of something called
-"generic functions" or "generic methods"
-(you may observe we made use of such a thing in extending
-handle-line).
-Many lispers believe that there is no need for message passing
-with generic methods and some advanced functional techniques,
-but in a concurrent environment message passing becomes useful
-again, especially when the communicating objects / actors are not
-in the same address space.)
+the line we want it to spit out to the channel).[fn:send-message-provenance]
 
 Normally in the actor model, we don't have direct references to
 an actor, only an identifier.
@@ -241,8 +232,8 @@ Indeed, we do have such a method, so we /could/ rewrite handle-line
 like so:
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     (irc-bot-send-line irc-bot channel
                        (format #f "Bawwwwk! ~a says: ~a" speaker line)))
 #+END_SRC
@@ -269,8 +260,8 @@ Whee, that looks like fun!
 To implement it, we're going to pull out Guile's pattern matcher.
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     (define my-name (irc-bot-username irc-bot))
     (define (looks-like-me? str)
       (or (equal? str my-name)
@@ -306,8 +297,8 @@ If you're getting the sense that we could make this a bit less wordy,
 you're right:
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     (define my-name (irc-bot-username irc-bot))
     (define (looks-like-me? str)
       (or (equal? str my-name)
@@ -360,6 +351,20 @@ What cool commands can you add?
   thing given chat bots being a fairly mundane novelty amongst hackers
   and teenagers everywhere a few decades ago.
 
+[fn:send-message-provenance]
+  8sync's name for sending a message, "<-", comes from older,
+  early lisp object oriented systems which were, as it turned out,
+  inspired by the actor model!
+  Eventually message passing was dropped in favor of something called
+  "generic functions" or "generic methods"
+  (you may observe we made use of such a thing in extending
+  handle-line).
+  Many lispers believe that there is no need for message passing
+  with generic methods and some advanced functional techniques,
+  but in a concurrent environment message passing becomes useful
+  again, especially when the communicating objects / actors are not
+  in the same address space.
+
 ** Writing our own actors
 
 Let's write the most basic, boring actor possible.
@@ -377,7 +382,7 @@ How about an actor that start sleeping, and keeps sleeping?
   (define (sleeper-loop actor message)
     (while (actor-alive? actor)
       (display "Zzzzzzzz....\n")
-      ;; Sleep for one second      
+      ;; Sleep for one second
       (8sleep (sleeper-sleep-secs actor))))
 
   (let* ((hive (make-hive))
@@ -386,11 +391,10 @@ How about an actor that start sleeping, and keeps sleeping?
 #+END_SRC
 
 We see some particular things in this example.
-One thing is that our <sleeper> actor has an actions slot.
+One thing is that our =<sleeper>= actor has an actions slot.
 This is used to look up what the "action handler" for a message is.
-We have to set the #:allocation to either #:each-subclass or #:class.
-(#:class should be fine, except there is [[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25211][a bug in Guile]] which keeps
-us from using it for now.)
+We have to set the #:allocation to either =#:each-subclass= or
+=#:class=.[fn:class-bug]
 
 The only action handler we've added is for =*init*=, which is called
 implicitly when the actor first starts up.
@@ -404,7 +408,7 @@ and will always yield to the scheduler.
 Our while loop also checks "actor-alive?" to see whether or not
 it is still registered.
 In general, if you keep a loop in your actor that regularly yields
-to the scheduler, you should check this.
+to the scheduler, you should check this.[fn:actor-alive-deprecated-soon]
 (An alternate way to handle it would be to not use a while loop at all
 but simply send a message to ourselves with "<-" to call the
 sleeper-loop handler again.
@@ -641,6 +645,16 @@ manager> Oh!  I guess you can go home then.
 worker> Whew!  Free at last.
 #+END_SRC
 
+[fn:class-bug]
+  #:class should be fine, except there is [[https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25211][a bug in Guile]] which keeps
+  us from using it for now.
+
+[fn:actor-alive-deprecated-soon]
+  Or rather, for now you should call =actor-alive?= if your code
+  is looping like this.
+  In the future, after an actor dies, its coroutines will
+  automatically be "canceled".
+
 ** Writing our own network-enabled actor
 
 So, you want to write a networked actor!
@@ -655,7 +669,8 @@ Well, luckily that's pretty easy, especially with all you know so far.
   (define-actor <telcmd> (<actor>)
     ((*init* telcmd-init)
      (*cleanup* telcmd-cleanup)
-     (new-client telcmd-new-client))
+     (new-client telcmd-new-client)
+     (handle-line telcmd-handle-line))
     (socket #:accessor telcmd-socket
             #:init-value #f))
 #+END_SRC
@@ -735,12 +750,12 @@ In our case, we politely close the socket when =<telcmd>= dies.
         (cond ((eof-object? line)
                (close client))
               (else
-               (telcmd-handle-line telcmd client
-                                   (string-trim-right line #\return))
+               (<- (actor-id telcmd) 'handle-line
+                   client (string-trim-right line #\return))
                (when (actor-alive? telcmd)
                  (loop)))))))
 
-  (define (telcmd-handle-line telcmd client line)
+  (define (telcmd-handle-line telcmd message client line)
     (match (string-split line #\space)
       (("") #f)  ; ignore empty lines
       (("time" _ ...)
@@ -765,7 +780,7 @@ agenda.[fn:setvbuf]
 The actual method called whenever we have a "line" of input is pretty
 straightforward... in fact it looks an awful lot like the IRC bot
 handle-line procedure we used earlier.
-No surprises there!
+No surprises there![fn:why-send-a-message-to-handle-line]
 
 Now let's run it:
 
@@ -819,7 +834,21 @@ Happy hacking!
   finishes handling one message.
   Our loop couldn't look quite like this though!
 
-** An intermission: about live hacking
+[fn:why-send-a-message-to-handle-line]
+  Well, there may be one surprise to a careful observer.
+  Why are we sending a message to ourselves?
+  Couldn't we have just dropped the argument of "message" to
+  telcmd-handle-line and just called it like any other procedure?
+  Indeed, we /could/ do that, but sending a message to ourself has
+  an added advantage: if we accidentally "break" the
+  telcmd-handle-line procedure in some way (say we add a fun new
+  command we're playing with it), raising an exception won't break
+  and disconnect the client's main loop, it'll just break the
+  message handler for that one line, and our telcmd will happily
+  chug along accepting another command from the user while we try
+  to figure out what happened to the last one.
+
+** An intermission on live hacking
 
 This section is optional, but highly recommended.
 It requires that you're a user of GNU Emacs.
@@ -857,13 +886,13 @@ Redefine run-bot like so:
                     (repl-path "/tmp/8sync-repl"))
     (define hive (make-hive))
     (define irc-bot
-      (bootstrap-actor* hive <my-irc-bot> "irc-bot"
-                        #:username username
-                        #:server server
-                        #:channels channels))
+      (bootstrap-actor hive <my-irc-bot>
+                       #:username username
+                       #:server server
+                       #:channels channels))
     (define repl-manager
-      (bootstrap-actor* hive <repl-manager> "repl"
-                          #:path repl-path))
+      (bootstrap-actor hive <repl-manager>
+                       #:path repl-path))
 
     (run-hive hive '()))
 #+END_SRC
@@ -929,8 +958,8 @@ Edit the respond section to see what channel it's really sending
 things to:
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     ;; [... snip ...]
     (define (respond respond-line)
       (<- (actor-id irc-bot) 'send-line (pk 'channel channel)
@@ -959,8 +988,8 @@ to looks like our own username that we respond back to the sender.
 (We can remove the pk now that we know what's going on.)
 
 #+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
+  (define-method (handle-line (irc-bot <my-irc-bot>) message
+                              speaker channel line emote?)
     ;; [... snip ...]
     (define (respond respond-line)
       (<- (actor-id irc-bot) 'send-line
@@ -1019,7 +1048,7 @@ Luckily, it turns out there's a clear relationship, based on real,
 actual theory!
 8sync is based on the [[https://en.wikipedia.org/wiki/Actor_model][actor model]] whereas fibers follows
 [[http://usingcsp.com/][Communicating Sequential Processes (CSP)]], which is a form of
-[[https://en.wikipedia.org/wiki/Process_calculus][process calculi]]. 
+[[https://en.wikipedia.org/wiki/Process_calculus][process calculi]].
 And it turns out, the
 [[https://en.wikipedia.org/wiki/Actor_model_and_process_calculi][relationship between the actor model and process calculi]] is well documented,
 and even more precisely, the