<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Bluish Coder: 3move</title>
 <link href="http://bluishcoder.co.nz/tag/3move/atom.xml" rel="self"/>
 <link href="http://bluishcoder.co.nz/"/>
 <updated>2018-01-10T15:35:12+13:00</updated>
 <id>http://bluishcoder.co.nz/</id>
 <author>
   <name>Bluishcoder</name>
   <email>admin@bluishcoder.co.nz</email>
 </author>

 
 <entry>
   <title>Exploring 3-Move - A LambdaMOO inspired environment</title>
   <link href="http://bluishcoder.co.nz/2017/04/09/exploring-3-move-a-lambdamoo-inspired-environment.html"/>
   <updated>2017-04-09T23:00:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2017/04/09/exploring-3-move-a-lambdamoo-inspired-environment</id>
   <content type="html">&lt;p&gt;I was a fan of &lt;a href=&quot;https://en.wikipedia.org/wiki/MUD&quot;&gt;MUDs&lt;/a&gt; from my earliest introduction to computers. I remember writing to &lt;a href=&quot;https://en.wikipedia.org/wiki/Richard_Bartle&quot;&gt;Richard Bartle&lt;/a&gt; when I was young asking about the possiblity of accessing &lt;a href=&quot;https://en.wikipedia.org/wiki/MUD1&quot;&gt;MUD1&lt;/a&gt; from New Zealand after having read about it in a magazine. The reply was very positive but unfortunately the cost of 300 baud modem access at international phone rates was prohibitive. It was later in life that my first use of the internet and a shell account on my ISP was to compile and run a MUD client.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/MOO&quot;&gt;MOO&lt;/a&gt; variants of MUDs are particularly interesting as they are multi user, programmable, interactive systems. They&#39;re like IRC where users can create objects, rooms and worlds by writing programs within the system. This resulted in systems with interesting programming systems with permission models for different levels of users. Content, including code, was stored in a persistent object database. &lt;a href=&quot;https://en.wikipedia.org/wiki/LambdaMOO&quot;&gt;LambdaMOO&lt;/a&gt; was a very popular instance of a MOO.&lt;/p&gt;

&lt;p&gt;A while back I stumbled across &lt;a href=&quot;http://homepages.kcbbs.gen.nz/tonyg/projects/3-move.html&quot;&gt;3-Move&lt;/a&gt;, a multi user networked online text-based programmable environment, by &lt;a href=&quot;http://homepages.kcbbs.gen.nz/tonyg/index.html&quot;&gt;Tony Garnock-Jones&lt;/a&gt;. It&#39;s a neat system that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistent object-oriented database&lt;/li&gt;
&lt;li&gt;A MOO inspired security model&lt;/li&gt;
&lt;li&gt;Prototype-based object-oriented language&lt;/li&gt;
&lt;li&gt;First-class functions, continuations and preemptive green threads.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There&#39;s not much written in the way of documentation on getting it running so this post documents how I got it working. It appears to not be actively developed anymore but it&#39;s a nice small system to learn from.&lt;/p&gt;

&lt;h2&gt;Building&lt;/h2&gt;

&lt;p&gt;Building 3-move requires cloning the source and running &lt;code&gt;make&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/tonyg/3-move
$ make
$ ./move/move
move [-t] &amp;lt;dbfilename&amp;gt; [&amp;lt;move-source-code-file&amp;gt; ...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This produces the &lt;code&gt;move&lt;/code&gt; executable which is the virtual machine and a &lt;code&gt;checkpoint-cleanup&lt;/code&gt; which is a helper program to clean up database checkpoint files.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;move&lt;/code&gt; executable requires a database as an argument. This database stores the state of the persistent world. It&#39;s loaded in memory when &lt;code&gt;move&lt;/code&gt; is run and can be saved by occasionally checkpointing the system. Optional arguments are &lt;code&gt;move&lt;/code&gt; source code files that are compiled and executed.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://github.com/tonyg/3-move/tree/master/db&quot;&gt;db&lt;/a&gt; directory are a number of &lt;code&gt;move&lt;/code&gt; source files that contain the code for a multi user virtual environment. The command parser, socket usage, line editor, etc are all written in these &lt;code&gt;move&lt;/code&gt; files.&lt;/p&gt;

&lt;h2&gt;Database&lt;/h2&gt;

&lt;p&gt;To create an initial database there is a &lt;code&gt;build&lt;/code&gt; script that creates a database with the content of the &lt;code&gt;move&lt;/code&gt; file. It can be run with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd db
$ ./build
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates the database in a file, &lt;code&gt;db&lt;/code&gt;, and a symbolic link to the &lt;code&gt;move&lt;/code&gt; executable in the current directory for easy execution. All the &lt;code&gt;build&lt;/code&gt; script does is run &lt;code&gt;move&lt;/code&gt; on files in the right order to build the database. It&#39;s equivalent to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./move db root.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db system.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db thing.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db login.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db player.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db room.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db exit.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db note.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db program.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
$ ./move db registry.move &amp;amp;&amp;amp; mv move.checkpoint.000 db
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each run of &lt;code&gt;move&lt;/code&gt; creates a new database called &lt;code&gt;move.checkout.000&lt;/code&gt;, containing the state of the old database plus any changes made by the &lt;code&gt;move file&lt;/code&gt;. This is then renamed back to &lt;code&gt;db&lt;/code&gt; and run again on the next file. The end result is a complete database with a default virtual environment.&lt;/p&gt;

&lt;h2&gt;Running&lt;/h2&gt;

&lt;p&gt;With the database built the system can be run with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./move db restart.move
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/db/restart.move&quot;&gt;restart.move&lt;/a&gt; calls &lt;code&gt;start-listening()&lt;/code&gt; to start the socket server accepting connections:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set-realuid(Wizard);
set-effuid(Wizard);

start-listening();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It calls the &lt;code&gt;set-realuid&lt;/code&gt; and &lt;code&gt;set-effuid&lt;/code&gt; functions to &lt;code&gt;Wizard&lt;/code&gt; before calling to ensure that the system can access the default &quot;Wizard&quot; user which has full permissions to call the socket related functions.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;start-listening&lt;/code&gt; is implemented in &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/db/login.move&quot;&gt;login.move&lt;/a&gt;. It creates a server socket that accepts connections on port &lt;code&gt;7777&lt;/code&gt;. It can be connected to via &lt;code&gt;telnet&lt;/code&gt;, &lt;code&gt;netcat&lt;/code&gt;, or similar program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ nc 127.0.0.1 7777
        _/      _/    _/_/_/    _/      _/  _/_/_/_/_/  
       _/_/  _/_/  _/      _/    _/  _/    _/       
      _/  _/  _/  _/      _/    _/  _/    _/_/_/        
     _/      _/  _/      _/      _/      _/         
    _/      _/    _/_/_/        _/      _/_/_/_/_/      

3-MOVE Copyright (C) 1997--2009 Tony Garnock-Jones.
This program comes with ABSOLUTELY NO WARRANTY; for details see
http://homepages.kcbbs.gen.nz/tonyg/projects/3-move.html.
This is free software, and you are welcome to redistribute it
under certain conditions; see http://github.com/tonyg/3-move for
details.


login: 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The database only contains one user, &lt;code&gt;Wizard&lt;/code&gt;, to begin with. It has no password:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;login: Wizard
Password: 

Logging in as player Wizard...

Welcome to MOVE.

Generic Room
~~~~~~~~~~~~
This is a nondescript room.
Wizard is here.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;@verbs&lt;/code&gt; command can be used to find out what commands can be sent to objects:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@verbs me
  Verbs defined on Wizard (#7) and it&#39;s parents:
    (Wizard (#7))
    @shutdown
    @checkpoint
    (Generic Player (#2))
    look
    @setpass &amp;lt;pass&amp;gt;
     ...

@verbs here
  Verbs defined on Generic Room (#3) and it&#39;s parents:
    (Generic Room (#3))
    say &amp;lt;sent&amp;gt;
    emote&amp;lt;sent&amp;gt;
    @@shout &amp;lt;sent&amp;gt;
      ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;@examine&lt;/code&gt; is another useful verb for finding out internal details of an object:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@examine me
  Wizard (#7) (owned by Wizard (#7))
  Location: #&amp;lt;object Generic Room (#3)&amp;gt;
  Contents: [Registry (#0), Generic Program (#6), Generic Note (#5), Generic Exit (#4),
  Generic Thing (#1)]
  Parent(s): Generic Player (#2)
  Methods: [@checkpoint-verb, @shutdown-verb]
  Slots: [verbs, connection, is-programmer, registry-number, name, awake]
  Verbs: [@shutdown-verb, @checkpoint-verb]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&#39;s important to set a password when first logging in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@setpass ********
  Password changed.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Users&lt;/h2&gt;

&lt;p&gt;A multi user environment without other users isn&#39;t much fun. Guest users can be added with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@build Guest as guest1
  You created an object.
  You named it &quot;guest1&quot;.
  It was registered as guest1 (#9).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are special users in that any login name of &lt;code&gt;guest&lt;/code&gt; will pick from the current guest users that are not logged in. This allows people to explore the system without creating a user. Specific users can also be created:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@build Player as chris
  You created an object.
  You named it &quot;chris&quot;.
  It was registered as chris (#10).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&#39;s an example interaction of the &lt;code&gt;chris&lt;/code&gt; user logging in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@setpass foo
  Password changed.
@describe chris
  Editing description of #&amp;lt;object chris (#10)&amp;gt;.
  Type .s to save, or .q to lose changes. .? is for help.
2&amp;gt; .l
  --- Current text:
  1&amp;gt; You see a player who needs to @describe %r.
2&amp;gt; .d 1
1&amp;gt; An amorphous blob shimmers in the light.
2&amp;gt; .s
  Setting description...
  Description set.

look at me

  chris
  ~~~~~
  An amorphous blob shimmers in the light.
  (chris is awake.)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Creating Rooms&lt;/h2&gt;

&lt;p&gt;Wizards can create rooms and routes to them with &lt;code&gt;@dig&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@dig here to Large Room as north
  You dig the backlink exit, named &quot;out&quot;, from &quot;Large Room&quot; to &quot;Generic Room (#3)&quot;.
  You dig the outward exit, named &quot;north&quot;, from &quot;Generic Room (#3)&quot; to &quot;Large Room&quot;.

look
  Generic Room
  ~~~~~~~~~~~~
  This is a nondescript room.
  chris, guest1 and Wizard are here.
  Obvious exits: north to Large Room

north
  Large Room
  ~~~~~~~~~~
  This is a nondescript room.
  Wizard is here.
  Obvious exits: out to Generic Room
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Normal users can create rooms but can&#39;t dig paths to the new room inside an existing room they didn&#39;t create themselves. They can use &lt;code&gt;go to&lt;/code&gt; to go to the room created and build up rooms from there. A friendly Wizard can link the rooms later if desired. The room logic is in &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/db/room.move&quot;&gt;room.move&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Programs&lt;/h2&gt;

&lt;p&gt;Programs can be written and executed within the environment. This is done by creating a &lt;code&gt;Program&lt;/code&gt; object, editing it and compiling it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@build Program as hello
  You created an object.
  You named it &quot;hello&quot;.
  It was registered as hello (#11).

edit hello
  Type .s to save, or .q to lose changes. .? is for help.
1&amp;gt; realuid():tell(&quot;Hello World\n&quot;);
2&amp;gt; .s
  Edit successful.

@compile hello
  Hello World
  Result: undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This &quot;hello world&quot; example gets the current user with &lt;code&gt;realuid&lt;/code&gt; and calls the &lt;code&gt;tell&lt;/code&gt; method which sends output to that users connection.&lt;/p&gt;

&lt;p&gt;The code for the &lt;code&gt;Program&lt;/code&gt; object is in &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/db/program.move&quot;&gt;program.move&lt;/a&gt;. Note that the &lt;code&gt;@compile&lt;/code&gt; verb wraps the code from the program inside a &quot;&lt;code&gt;function (TARGET) { ...code here... }&lt;/code&gt;&quot;. &lt;code&gt;TARGET&lt;/code&gt; can be set using the &lt;code&gt;@target&lt;/code&gt; verb on a program. This enables writing programs that can add verbs to objects. The &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/db/program.move&quot;&gt;tricks&lt;/a&gt; subdirectory has some example of this, for example &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/tricks/ps.verbs.move&quot;&gt;ps.verbs.move&lt;/a&gt; that adds the &lt;code&gt;@ps&lt;/code&gt; verb to the target:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define method (TARGET) @ps-verb(b) {
  define player = realuid();
  if (player != TARGET) {
    player:tell(&quot;You don&#39;t have permission to @ps, I&#39;m sorry.\n&quot;);
  } else {
    define tab = get-thread-table();

    player:mtell([&quot;Process table:\n&quot;] + map(function(p) {
      &quot; #&quot; + get-print-string(p[0]) + &quot;\t&quot; +
    p[1].name + &quot;\t\t&quot; +
    get-print-string(p[2]) + &quot;\t&quot; +
    get-print-string(p[3]) + &quot;\n&quot;;
    }, tab));
  }
}
TARGET:add-verb(#this, #@ps-verb, [&quot;@ps&quot;]);  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If that text is copied and pasted into a program, then &lt;code&gt;@ps&lt;/code&gt; can be added to an object with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@build Program as psprog
  You created an object.
  You named it &quot;psprog&quot;.
  It was registered as psprog (#13).

edit psprog
  Type .s to save, or .q to lose changes. .? is for help.
1&amp;gt; ...paste program code above...
2&amp;gt; .s

@target psprog at me
  You target psprog (#13) at Wizard (#7).

@compile psprog
  Result: true

@verbs me
  Verbs defined on Wizard (#7) and it&#39;s parents:
    (Wizard (#7))
    @shutdown
    @checkpoint
    @ps
    ...

@ps
  Process table:
   #1   Wizard      false   2
   #2   Wizard      false   0
   #3   chris       false   1
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Checkpointing&lt;/h2&gt;

&lt;p&gt;All changes to the system are done in memory. A &lt;code&gt;checkpoint&lt;/code&gt; method should be called occasionally to save the current state of the database. An example of how to do this is in &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/tricks/checkpoint.move&quot;&gt;checkpoint.move&lt;/a&gt; but it can also be done by any Wizard calling &lt;code&gt;@checkpoint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Checkpoints don&#39;t overwrite the existing database - they save to a new file of the form &lt;code&gt;move.checkpoint.000&lt;/code&gt;, where &lt;code&gt;000&lt;/code&gt; is an incrementing number. When restarting a system it&#39;s important to use the last checkpoint to start from.&lt;/p&gt;

&lt;h2&gt;Programming Language&lt;/h2&gt;

&lt;p&gt;The programming language used by 3-Move is undocumented but it&#39;s pretty easy to follow from the examples. The primitives can be seen in the &lt;code&gt;PRIM.*.c&lt;/code&gt; files in the &lt;a href=&quot;https://github.com/tonyg/3-move/tree/master/move&quot;&gt;move&lt;/a&gt; directory. Functions are of the form:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define function this-is-a-function(arg1, argn) {
   ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The system uses a prototype object system. Objects are created by calling &lt;code&gt;clone&lt;/code&gt; on an existing object:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Create an object cloned from the Root object
define c = Root:clone();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Objects can have fields. These are defined as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Define a blah field of the new object and give it a value
define (c) blah = &quot;foo&quot;;

// Access the blah field
c.blah;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Objects can have methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Define a constructor for &#39;c&#39; which gets called when cloned
define method (c) initialize() {
  as(Root):initialize();
  this.blah = &quot;new blah&quot;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fields are accessed using the dot operator (&lt;code&gt;.&lt;/code&gt;) and methods with the colon operator (&lt;code&gt;:&lt;/code&gt;). There are separate namespace for fields and methods.&lt;/p&gt;

&lt;p&gt;Objects and fields can have flags set to control permissions. An example from the source:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Only the owner of an object can see the connection field
define (Player) connection = null;
set-slot-flags(Player, #connection, O_OWNER_MASK);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The flags are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define O_OWNER_MASK = 0x00000F00;
define O_GROUP_MASK = 0x000000F0;
define O_WORLD_MASK = 0x0000000F;
define O_ALL_R  = 0x00000111;
define O_ALL_W  = 0x00000222;
define O_ALL_X  = 0x00000444;

define O_OWNER_R    = 0x00000100;
define O_OWNER_W    = 0x00000200;
define O_OWNER_X    = 0x00000400;
define O_GROUP_R    = 0x00000010;
define O_GROUP_W    = 0x00000020;
define O_GROUP_X    = 0x00000040;
define O_WORLD_R    = 0x00000001;
define O_WORLD_W    = 0x00000002;
define O_WORLD_X    = 0x00000004;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From within a method it&#39;s possible to query the user that called it and from there dynamically check permissions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define method (Thing) add-alias(n) {
  if (caller-effuid() != owner(this) &amp;amp;&amp;amp; !privileged?(caller-effuid()))
    return false;

  this.aliases = this.aliases + [n];
  return true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This ensures that &lt;code&gt;add-alias&lt;/code&gt; can only be called on the &lt;code&gt;Thing&lt;/code&gt; object if the caller is the owner of the object and if they are a privileged user. Another example is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define method (Thing) add-verb(selfvar, methname, pattern) {
  define c = caller-effuid();
  define fl = object-flags(this);

  if ((fl &amp;amp; O_WORLD_W == O_WORLD_W) ||
      ((fl &amp;amp; O_GROUP_W == O_GROUP_W) &amp;amp;&amp;amp; in-group-of(c, this)) ||
      ((fl &amp;amp; O_OWNER_W == O_OWNER_W) &amp;amp;&amp;amp; c == owner(this)) ||
      privileged?(c)) {
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here &lt;code&gt;add-verb&lt;/code&gt; can only be called if the object is world writeable, or group writeable and the caller is a member of the group, or owner writeable and the caller is the owner, or the caller is privileged.&lt;/p&gt;

&lt;p&gt;Objects can also have flags set:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define method (Root) clone() {
  define n = the-clone(this);
  if (n) {
    set-object-flags(n, O_NORMAL_FLAGS);
    n:initialize();
  }
  n;
}
set-setuid(Root:clone, false);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Anonymous functions and higher order functions are available. Unfortunately there&#39;s no REPL but snippets can be tested in &lt;code&gt;Program&lt;/code&gt; objects when logged in, or added to a &lt;code&gt;move&lt;/code&gt; file and executed against the database. The result will be printed as part of the output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define function reduce(f, st, vec) {
  define i = 0;

  while (i &amp;lt; length(vec)) {
    st = f(st, vec[i]);
    i = i + 1;
  }

  st;
}

reduce(function(acc, al) acc + al, 0, [1, 2, 3, 4, 5]);

$ ./move x reduce.move 
importing test2.move
--&amp;gt; true
--&amp;gt; 15
--&amp;gt;! the compiler returned NULL.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lightweight threads are spawned using &lt;code&gt;fork&lt;/code&gt; and &lt;code&gt;fork/quota&lt;/code&gt;. The first version, &lt;code&gt;fork&lt;/code&gt; takes a function to spawn in the background. It uses a default CPU quota of 15,000 cycles before it terminates:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;fork(function () {
    while (true) {
      ...do something...
      // sleep for one second
      sleep(1);
    }
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Threads are saved in the database when checkpointed and resumed when the database is started. &lt;code&gt;fork/quota&lt;/code&gt; allows setting a quota value other than the default of 15,000 cycles. It also allows three special values. A quota value of &lt;code&gt;0&lt;/code&gt; means the thread should exit as soon as possible. &lt;code&gt;-1&lt;/code&gt; means the thread should run forever, with no quota, and can be checkpointed and resumed on restart like normal threads. A value of &lt;code&gt;-2&lt;/code&gt; means the thread runs forever but is not checkpointed and therefore not resumed at startup.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#define VM_STATE_DYING          0
#define VM_STATE_DAEMON         -1
#define VM_STATE_NOQUOTA        -2

fork/quota(function () {
    while (true) {
      ...do something...
      // sleep for one second
      sleep(1);
    }
  }, VM_STATE_DAEMON);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The language has support for first class continuations via the &lt;code&gt;call/cc&lt;/code&gt; primitive. This works the same as the scheme &lt;a href=&quot;https://en.wikipedia.org/wiki/Call-with-current-continuation&quot;&gt;call-with-current-continuation&lt;/a&gt; function. An example from the wikipedia page:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;define function foo(ret) {
  ret(2);
  3;
}

foo(function (x) x); // Returns 3
call/cc(foo);        // Returns 2
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Tricks&lt;/h2&gt;

&lt;p&gt;There is a &lt;a href=&quot;https://github.com/tonyg/3-move/tree/master/tricks&quot;&gt;tricks&lt;/a&gt; directory that contains utility code and examples. This includes an &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/tricks/httpd.move&quot;&gt;http&lt;/a&gt; server written in &lt;code&gt;move&lt;/code&gt;, code for sending mail via &lt;a href=&quot;https://github.com/tonyg/3-move/blob/master/tricks/smtp.move&quot;&gt;smtp&lt;/a&gt;, and some bot examples.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The move language looks quite nice. I suspect it&#39;d be useful for things other than virtual worlds - server side applications that can be extended with scripts safely are a common use case. I&#39;ve put an example server on &lt;code&gt;bluishcoder.co.nz&lt;/code&gt; port &lt;code&gt;7777&lt;/code&gt; to experiment with. There are a few guest accounts configured:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ nc bluishcoder.co.nz 7777
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&#39;s a port for SSL connections on 7778 that can be connected via:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ openssl s_client -connect bluishcoder.co.nz:7778
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The SSL connection was set up on the server using &lt;a href=&quot;http://www.dest-unreach.org/socat/&quot;&gt;socat&lt;/a&gt; to forward to the 7777 port:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ openssl genrsa -out move.key 2048
$ openssl req -new -key move.key -x509 -days 3653 -out move.crt
$ socat openssl-listen:7778,reuseaddr,pf=ip4,fork,cert=./move.pem,verify=0 TCP:127.0.0.1:7777
&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 
</feed>
