doc: Add a note about actor-alive? being likely to be deprecated.
[8sync.git] / doc / 8sync-new-manual.org
index 955e50ec28adf863dae86ed9f9f628c866d6f5bd..844653fa0b6a3da7eedd30ad376775d65fcc5759 100644 (file)
@@ -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>))
 
 #+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)
     (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.
 (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!
 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!
@@ -159,7 +164,7 @@ nothing is going to happen.
 We can run it like:
 
 #+BEGIN_SRC scheme
 We can run it like:
 
 #+BEGIN_SRC scheme
-(run-bot #:username "some-bot-username") ; be creative!
+(run-bot #:username "some-bot-name") ; be creative!
 #+END_SRC
 
 Assuming all the tubes on the internet are properly connected, you
 #+END_SRC
 
 Assuming all the tubes on the internet are properly connected, you
@@ -174,8 +179,8 @@ Let's get it to echo whatever we say back to us.
 Change handle-line to this:
 
 #+BEGIN_SRC scheme
 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
     (<- (actor-id irc-bot) 'send-line channel
         (format #f "Bawwwwk! ~a says: ~a" speaker line)))
 #+END_SRC
@@ -241,8 +246,8 @@ Indeed, we do have such a method, so we /could/ rewrite handle-line
 like so:
 
 #+BEGIN_SRC scheme
 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
     (irc-bot-send-line irc-bot channel
                        (format #f "Bawwwwk! ~a says: ~a" speaker line)))
 #+END_SRC
@@ -253,24 +258,6 @@ so that /other/ actors may participate in communicating with IRC
 through our IRC bot.
 
 Anyway, our current message handler is simply too annoying.
 through our IRC bot.
 
 Anyway, our current message handler is simply too annoying.
-What would be much more interesting is if we could recognize
-when an actor could repeat messages /only/ when someone is speaking
-to it directly.
-Luckily this is an easy adjustment to make.
-
-#+BEGIN_SRC scheme
-  (define-method (handle-line (irc-bot <my-irc-bot>) speaker channel
-                              line emote?)
-    (define my-name (irc-bot-username irc-bot))
-    (define (looks-like-me? str)
-      (or (equal? str my-name)
-          (equal? str (string-concatenate (list my-name ":")))))
-    (when (looks-like-me?)
-      (<- (actor-id irc-bot) 'send-line channel
-          (format #f "Bawwwwk! ~a says: ~a" speaker line))))
-#+END_SRC
-
-This is relatively straightforward, but it isn't very interesting.
 What we would really like to do is have our bot respond to individual
 "commands" like this:
 
 What we would really like to do is have our bot respond to individual
 "commands" like this:
 
@@ -287,8 +274,8 @@ Whee, that looks like fun!
 To implement it, we're going to pull out Guile's pattern matcher.
 
 #+BEGIN_SRC scheme
 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)
     (define my-name (irc-bot-username irc-bot))
     (define (looks-like-me? str)
       (or (equal? str my-name)
@@ -324,8 +311,8 @@ If you're getting the sense that we could make this a bit less wordy,
 you're right:
 
 #+BEGIN_SRC scheme
 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)
     (define my-name (irc-bot-username irc-bot))
     (define (looks-like-me? str)
       (or (equal? str my-name)
@@ -376,7 +363,7 @@ What cool commands can you add?
   At the time of writing, venture capital awash startups are trying to
   turn chatbots into "big business"... a strange (and perhaps absurd)
   thing given chat bots being a fairly mundane novelty amongst hackers
   At the time of writing, venture capital awash startups are trying to
   turn chatbots into "big business"... a strange (and perhaps absurd)
   thing given chat bots being a fairly mundane novelty amongst hackers
-  and teenagers everywhere in the 1990s.
+  and teenagers everywhere a few decades ago.
 
 ** Writing our own actors
 
 
 ** Writing our own actors
 
@@ -422,7 +409,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
 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.
 (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.
@@ -544,7 +531,6 @@ which does not block the rest of the program from running.
 Let's try applying that to our own code by turning our manager
 into a micromanager.
 
 Let's try applying that to our own code by turning our manager
 into a micromanager.
 
-#+END_SRC
 #+BEGIN_SRC scheme
   ;;; Update this method
   (define (manager-assign-task manager message difficulty)
 #+BEGIN_SRC scheme
   ;;; Update this method
   (define (manager-assign-task manager message difficulty)
@@ -614,6 +600,20 @@ Of course, we need to update our worker accordingly as well.
 everywhere as we are in this program... that's just to make the
 examples more illustrative.)
 
 everywhere as we are in this program... that's just to make the
 examples more illustrative.)
 
+"<-reply" is what actually returns the information to the actor
+waiting on the reply.
+It takes as an argument the actor sending the message, the message
+it is in reply to, and the rest of the arguments are the "body" of
+the message.
+(If an actor handles a message that is being "waited on" but does not
+explicitly reply to it, an auto-reply with an empty body will be
+triggered so that the waiting actor is not left waiting around.)
+
+The last thing to note is the call to "self-destruct".
+This does what you might expect: it removes the actor from the hive.
+No new messages will be sent to it.
+Ka-poof!
+
 Running it is the same as before:
 
 #+BEGIN_SRC scheme
 Running it is the same as before:
 
 #+BEGIN_SRC scheme
@@ -646,19 +646,11 @@ manager> Oh!  I guess you can go home then.
 worker> Whew!  Free at last.
 #+END_SRC
 
 worker> Whew!  Free at last.
 #+END_SRC
 
-"<-reply" is what actually returns the information to the actor
-waiting on the reply.
-It takes as an argument the actor sending the message, the message
-it is in reply to, and the rest of the arguments are the "body" of
-the message.
-(If an actor handles a message that is being "waited on" but does not
-explicitly reply to it, an auto-reply with an empty body will be
-triggered so that the waiting actor is not left waiting around.)
-
-The last thing to note is the call to "self-destruct".
-This does what you might expect: it removes the actor from the hive.
-No new messages will be sent to it.
-Ka-poof!
+[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
 
 
 ** Writing our own network-enabled actor
 
@@ -674,7 +666,8 @@ Well, luckily that's pretty easy, especially with all you know so far.
   (define-actor <telcmd> (<actor>)
     ((*init* telcmd-init)
      (*cleanup* telcmd-cleanup)
   (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
     (socket #:accessor telcmd-socket
             #:init-value #f))
 #+END_SRC
@@ -754,12 +747,12 @@ In our case, we politely close the socket when =<telcmd>= dies.
         (cond ((eof-object? line)
                (close client))
               (else
         (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)))))))
 
                (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" _ ...)
     (match (string-split line #\space)
       (("") #f)  ; ignore empty lines
       (("time" _ ...)
@@ -784,7 +777,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.
 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:
 
 
 Now let's run it:
 
@@ -838,6 +831,20 @@ Happy hacking!
   finishes handling one message.
   Our loop couldn't look quite like this though!
 
   finishes handling one message.
   Our loop couldn't look quite like this though!
 
+[fn:why-send-a-message-to-handle-line]
+  Well, there may be one surprise to the astute 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: about live hacking
 
 This section is optional, but highly recommended.
 ** An intermission: about live hacking
 
 This section is optional, but highly recommended.
@@ -948,8 +955,8 @@ Edit the respond section to see what channel it's really sending
 things to:
 
 #+BEGIN_SRC scheme
 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)
     ;; [... snip ...]
     (define (respond respond-line)
       (<- (actor-id irc-bot) 'send-line (pk 'channel channel)
@@ -978,8 +985,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
 (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
     ;; [... snip ...]
     (define (respond respond-line)
       (<- (actor-id irc-bot) 'send-line