<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>The Beta Blog</title>
    <link>http://www.blit.ca/blog</link>
    <description>I have a cunning plan...</description>
    <pubDate>Sun, 20 Oct 2024 14:20:43 -0400</pubDate>
    <item>
      <title>Site update</title>
      <link>http://www.blit.ca/blog/h11dju8okz/Site_update.html</link>
      <description>&lt;p&gt;I have now updated &lt;a href=&quot;https://codeberg.org/suetanvil/jj&quot;&gt;jj&lt;/a&gt; (the
software that runs this blog) to be slightly less broken.  It is also
now on &lt;a href=&quot;http://codeberg.org&quot;&gt;http://codeberg.org&lt;/a&gt; instead of &lt;a href=&quot;http://github.com&quot;&gt;http://github.com&lt;/a&gt;, although
the latter repository is still archived.&lt;/p&gt;

&lt;p&gt;This will be of interest to the zero people who use this software and
are not me.&lt;/p&gt;
</description>
      <pubDate>Sun, 20 Oct 2024 18:17:15 -0000</pubDate>
      <guid>h11dju8okz</guid>
      <dc:date>2024-10-20T18:17:15Z</dc:date>
    </item>
    <item>
      <title>Loom: A Programming Language</title>
      <link>http://www.blit.ca/blog/gqr0ks77yz/Loom__A_Programming_Language.html</link>
      <description>&lt;p&gt;I&amp;#39;m a programming language &lt;s&gt;nerd&lt;/s&gt; enthusiast, and one of the ways
this manifests itself is in the occasional urge to design a new
language. There have been
&lt;a href=&quot;http://www.blit.ca/blog/fdey966ldd/Sic__Yet_Another_Mediocre_Small_Lisp_Dialect.html&quot;&gt;multiple&lt;/a&gt;
&lt;a href=&quot;http://blit.ca/deck.html&quot;&gt;such&lt;/a&gt; &lt;a href=&quot;http://blit.ca/tulip.html&quot;&gt;attempts&lt;/a&gt;
in my past and I succumbed to the urge again last year.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the result. It&amp;#39;s called Loom.&lt;/p&gt;

&lt;p&gt;The initial implementation is available
&lt;a href=&quot;https://codeberg.org/suetanvil/loom&quot;&gt;here&lt;/a&gt;, along with a &lt;a href=&quot;https://codeberg.org/suetanvil/loom/src/branch/main/doc/docsrc/lang-ref.org&quot;&gt;language
reference&lt;/a&gt;
and &lt;a href=&quot;https://codeberg.org/suetanvil/loom/src/branch/main/doc/lib-ref.md&quot;&gt;library
reference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want a more gentle introduction to it, read on.&lt;/p&gt;

&lt;p&gt;This post is mostly about the ideas behind it but it can also serve as a
wierdly overthought tutorial.&lt;/p&gt;

&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;Roughly speaking, Loom is a dialect of Smalltalk with C++-style syntax.
Its goal is to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Purely object-oriented in the Smalltalk sense&lt;/li&gt;
&lt;li&gt;  Homoiconic&lt;/li&gt;
&lt;li&gt;  Minimal&lt;/li&gt;
&lt;li&gt;  Transparent&lt;/li&gt;
&lt;li&gt;  Easy to implement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core ideas were stolen from Smalltalk when they left the doors
unlocked one night while the syntax was accidentally-on-purpose stolen
from &lt;a href=&quot;https://supercollider.github.io/&quot;&gt;sclang&lt;/a&gt;. I also shoplifted some
useful concepts from Ruby, and a few Lisp ideas may also have somehow
found their way into my bag.&lt;/p&gt;

&lt;p&gt;The three main ideas behind Loom are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Everything is an object.&lt;/li&gt;
&lt;li&gt; Everything is done by sending a message&lt;sup id=&quot;fnref1&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; to an object.&lt;/li&gt;
&lt;li&gt; Both compiling and running Loom code are simple enough processes
that you can hold them in your head.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;If you clone and (successfully) build the sources linked above, you&amp;#39;ll
have the Loom interpreter. When run with no arguments, it will drop into
an interactive session (aka a &lt;q&gt;REPL&lt;/q&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./src/loom
Loom REPL. Hooray!

&amp;gt; 3 + 4
7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(It helps to have rlwrap installed; the script in &lt;code&gt;src/loom&lt;/code&gt; will use it
if it&amp;#39;s available.)&lt;/p&gt;

&lt;p&gt;You quit it with an EOF character (CTRL+D on *nix).&lt;/p&gt;

&lt;p&gt;And if you run it with a Loom program, it will attempt to execute it, as
one does:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./src/loom examples/sieve.loom 40
Solving up to 40...
Primes up to 40: 
    2 3 5 7 11 13 17 19 23 29 31 37 
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay, onward to the language itself. Let&amp;#39;s start with some basic stuff:&lt;/p&gt;

&lt;h2&gt;Basic Stuff&lt;/h2&gt;

&lt;p&gt;Comments begin with &lt;code&gt;#&lt;/code&gt; or &lt;code&gt;//&lt;/code&gt; and go to the end of the line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// comment
# also a comment
2 + 3;  // comment after a statement
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(I just couldn&amp;#39;t pick a favourite.)&lt;/p&gt;

&lt;p&gt;Numbers and strings are as you&amp;#39;d expect from a C-style syntax:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;123                     # Decimal integer
420.69                  # Decimal float
0xBADCAFE               # Hex integer
0b1011                  # Binary integer

&amp;quot;Hello!\nworld!\n&amp;quot;      # Some C-style escapes are supported
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;#39;s also syntax for creating symbols and vectors. These look like
literals but aren&amp;#39;t:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[1, 2, 3]               # Vector (i.e. array)
:foo                    # The symbol &amp;#39;foo&amp;#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Symbols represent names within the system, just like in Lisp, Smalltalk,
Ruby, and other right-thinking languages.&lt;/p&gt;

&lt;p&gt;And Vectors are what I call arrays, because I&amp;#39;m pretentious. And also
because I&amp;#39;m reserving the word &lt;q&gt;Array&lt;/q&gt; for a possible future type that&amp;#39;s
more primitive. (Vectors can be resized in place; arrays can&amp;#39;t. In the
future, I may want to implement Vectors around Array instances so I
don&amp;#39;t need to use the host system&amp;#39;s types. But I digress.)&lt;/p&gt;

&lt;p&gt;Names (used for variables and methods) follow the standard C convention:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;foo_bar_quux
_fooBarQuux42Baz
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is, anything matching the regexp &lt;code&gt;/^[_a-zA-Z][_a-zA-Z0-9]*/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Any variable name beginning with an upper-case letter is a constant:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Pi = 3.14159
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(This also works for method arguments and locals; the latter isn&amp;#39;t
useful and is kind of a bug.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are a few well-known constants (&lt;code&gt;Self&lt;/code&gt;, &lt;code&gt;True&lt;/code&gt;, &lt;code&gt;False&lt;/code&gt;,
&lt;code&gt;Nil&lt;/code&gt;, and &lt;code&gt;Here&lt;/code&gt;) whose lowercase names (&lt;code&gt;self&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;,
etc.) are reserved by the parser and expanded into their upper-case
versions. So (e.g.) &lt;code&gt;nil&lt;/code&gt; is just another way of writing &lt;code&gt;Nil&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any character (almost) can be part of a name if it&amp;#39;s quoted with
backtick characters (&lt;code&gt;`&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;`$20, same as in town` = 20;
PoliteObject.new.`please initialize this instance`();
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This last property leads to some clever hackery we can do with syntax.&lt;/p&gt;

&lt;h2&gt;Message syntax&lt;/h2&gt;

&lt;p&gt;Sending a message to an object follows the usual C++-style syntax we
know and love:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;object.message(arg1, arg2, arg3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since this is the &lt;strong&gt;only&lt;/strong&gt; thing you can do, Loom coding (and reading)
would normally be a huge slog. We work around this in a number of ways,
mostly by fiddling with the syntax.&lt;/p&gt;

&lt;p&gt;For example, consider some basic arithmetic:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3.mult(4).add(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can (and do) use backticks and give the methods more operator-like
names:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3.`*`(4).`+`(1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and this is slightly better but still not very readable.&lt;/p&gt;

&lt;p&gt;So the parser&lt;sup id=&quot;fnref2&quot;&gt;&lt;a href=&quot;#fn2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; treats any token made of &lt;q&gt;operator&lt;/q&gt; characters as
implying the &lt;q&gt;`` .`...` ``&lt;/q&gt; part. And if there&amp;#39;s no open parenthesis
token (&lt;q&gt;`(`&lt;/q&gt;) afterward, it treats this as equivalent to taking the next
token and wrapping the parens around that.&lt;/p&gt;

&lt;p&gt;Which means the above can be written as&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3 * 4 + 1;
3 + (4) + 1;
3 + 4 + (1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This also means that Loom doesn&amp;#39;t need brackets&lt;sup id=&quot;fnref3&quot;&gt;&lt;a href=&quot;#fn3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. If you need to
change the order of evaluation, you can use the argument list parens:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a + (b * c) + (d * e);

// Equivalent to
a.`+`(b.`+`(c)).`+`(d.`+`(e));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We do other things with syntax. If a (non-operator) message has no
arguments, it&amp;#39;s safe to leave off the trailing parens:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;b = a.foo;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So getter methods are basically free. For setters, the parser looks for
a trailing &lt;code&gt;=&lt;/code&gt; token and if it finds it, first renames the message to
have a trailing underscore and then passes the expression after the &lt;code&gt;=&lt;/code&gt;
as its argument. The following are equivalent:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;b.foo = bobo.count + 1;
b.foo_(bobo.count() + 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Semi-related, C-style array access syntax gets expanded into &lt;code&gt;at&lt;/code&gt; and
&lt;code&gt;atPut&lt;/code&gt; message sends:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x = a[n + 1];
// is equivalent to
x = a.at(n + 1);

x[n + 1] = 42;
// is equivalent to
x.atPut(n + 1, 42);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So vector access looks the way you&amp;#39;d expect it to, but so does the (very
slow) Dictionary class. Anything that implements &lt;code&gt;at&lt;/code&gt; and &lt;code&gt;atPut&lt;/code&gt; can be
accessed with this syntax.&lt;/p&gt;

&lt;p&gt;Okay, onward to the deep end.&lt;/p&gt;

&lt;h2&gt;Quoting&lt;/h2&gt;

&lt;p&gt;Loom does Lisp-style quoting. You mostly don&amp;#39;t need to worry about it
unless you&amp;#39;re poking around the internals, but as I intend to do just
that, this is necessary.&lt;/p&gt;

&lt;p&gt;The syntax for a quoted expression is the expression surrounded by
special brackets &lt;code&gt;:(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt;. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x = :( foo );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quotes keep the things between the brackets from being evaluated. So in
the above snippet, &lt;code&gt;x&lt;/code&gt; gets the &lt;strong&gt;symbol&lt;/strong&gt; &lt;code&gt;foo&lt;/code&gt; instead of the value of
the variable named &lt;q&gt;foo&lt;/q&gt;.&lt;/p&gt;

&lt;p&gt;(And yes, the &lt;code&gt;:foo&lt;/code&gt; syntax above is just shorthand for &lt;code&gt;:(foo)&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;Most Loom objects just evaluate to themselves, so quoting them has no
effect. The exceptions are symbols (as above), message send expressions,
and quoted expressions themselves.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s one extra bit of quote-related syntax. A Vector expression
prefixed with a colon (&lt;code&gt;:[&lt;/code&gt; instead of &lt;code&gt;[&lt;/code&gt;) is equivalent to quoting
each element of the vector. The following are equivalent:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:[a, b, c]
[:a, :b, :c]
Vector.with(:a, :b, :c)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Quotes end up being vital for a lot of metaprogramming-related things,
and since the underlying machinery of Loom is already based on
metaprogramming, we need them.&lt;/p&gt;

&lt;p&gt;(I initially tried to avoid adding this feature. I thought I could
simply decompose each object into an expression that recreated it, so
that (e.g.) &lt;code&gt;:foo&lt;/code&gt; would expand to &lt;code&gt;&amp;quot;foo&amp;quot;.intern&lt;/code&gt;. This &lt;strong&gt;might&lt;/strong&gt; be
viable, but debugging any kind of metaprogramming was a nightmare
problem that Quote mostly removed.)&lt;/p&gt;

&lt;h2&gt;Objects and Classes&lt;/h2&gt;

&lt;p&gt;Now, let&amp;#39;s talk about object-oriented programming. Here&amp;#39;s a class
definition:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def ContactInfo = Object.subclass(:[name, address, work_phone,
                                    home_phone, tags]);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;#39;s start to the left of the &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;def&lt;/code&gt; keyword defines a global constant, &lt;code&gt;ContactInfo&lt;/code&gt; and assigns
the result of the expression after the &lt;code&gt;=&lt;/code&gt; to it. (&lt;code&gt;def&lt;/code&gt; is syntax
that expands to a call to &lt;code&gt;Here.defglobal(...)&lt;/code&gt;.  I&amp;#39;ll get to &lt;code&gt;Here&lt;/code&gt;
later.)&lt;/p&gt;

&lt;p&gt;To the right, we see &lt;code&gt;Object&lt;/code&gt;. This is the root class which, like all
other classes, is an object. Its method &lt;code&gt;subclass&lt;/code&gt; creates the new
class and its instance variables (aka &lt;q&gt;slots&lt;/q&gt;) are defined by the
array of symbols &lt;code&gt;subclass&lt;/code&gt; receives as its first argument.&lt;/p&gt;

&lt;p&gt;Most classes have an initializer method (&lt;q&gt;constructor&lt;/q&gt; in C++-speak):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::initialize = { | name_arg |
    name = name_arg;
    tags = [];
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is an ordinary method but it gets called by the class&amp;#39;s
instantiation method, &lt;code&gt;new&lt;/code&gt;; its arguments (the name(s) between the &lt;code&gt;|&lt;/code&gt;
characters) are all passed to &lt;code&gt;initialize&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Ringo = ContactInfo.new(&amp;quot;Ringo Starr&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instance variables are private to the object, so to get at them from
outside, we&amp;#39;ll need to add a getter and setter method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::name = { return name };
ContactInfo::name_ = { | new_name | return name = new_name };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Recall that something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Ringo.name = &amp;quot;Richard Starkey&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;gets expanded to a call to &lt;code&gt;name_&lt;/code&gt;, the setter.)&lt;/p&gt;

&lt;p&gt;Loom actually has built-in shorthand for this (and also the read-only
and write-only variants), so you&amp;#39;ll rarely need to write them by hand.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo.accessible(:address);
ContactInfo.accessible(:work_phone);
ContactInfo.accessible(:home_phone);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Methods can also take variadic arguments:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::tag = {|*all_tags|
  tags = tags + all_tags;
}
Ringo.tag(:ringo, :the_best_drummer_in_liverpool);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;They also (obviously) have local variables, declared between a second,
optional pair of pipe (&lt;code&gt;|&lt;/code&gt;) characters:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::set_field_count = { ||
    | sum |
    sum = tags.size;
    [name, address, work_phone, home_phone].each{|fld|
        fld.is_nil.not .if { sum = sum + 1 }
    };

    return sum;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, we need to also specify an empty argument list.
However, it&amp;#39;s safe to omit empty argument lists if the resulting code
is unambiguous.  (This is any case except for when there are
temporaries but no arguments.)&lt;/p&gt;

&lt;p&gt;We can also add methods to individual objects:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Ringo::*is_pete_best = { return false };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This includes classes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::*new_beatle = { return self.new(&amp;quot;Paul McCartney&amp;quot;) };
def Paul = ContactInfo.new_beatle;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of this sytax for defining new methods expands into ordinary
message send expressions.  For example, this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::dial = { ... }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;expands into something like this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo.inner_add_method(:dial, ...);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So all of this is available for metaprogramming.&lt;/p&gt;

&lt;h2&gt;Sending Messages&lt;/h2&gt;

&lt;p&gt;In addition to the language&amp;#39;s message-send syntax, message-based
languages typically provide a way to programmatically send a message
to an object. This is typically done by method(s) of the base class
that take the name and message arguments as their own arguments, then
send them and return the result. This is how Loom does it as well.&lt;/p&gt;

&lt;p&gt;In Loom, there are two methods of class &lt;code&gt;Object&lt;/code&gt;: &lt;code&gt;send&lt;/code&gt; and &lt;code&gt;sendv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;send&lt;/code&gt; is a variadic method whose first argument is the message name (a
symbol) and the remaining argument are passed to the message. For
example,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3.send(:`+`, 4)             # 7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is equivalent to either of&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3 + 4
3.`+`(4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But because the message is an argument, we can compute it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;msg = self.select_at_random(:[`+`, `-`, `*`, `/`]);
3.send(msg, 4)              # ???
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;sendv&lt;/code&gt; is like &lt;code&gt;send&lt;/code&gt;, but not variadic.  Instead, it takes exactly
two arguments where the second is a vector containing the message&amp;#39;s
arguments. With &lt;code&gt;sendv&lt;/code&gt;, the above examples would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3.sendv(:`+`, [4])          # 7

msg = self.select_at_random(:[`+`, `-`, `*`, `/`]);
3.sendv(msg, [4])           # ???
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is important because, while Loom methods can take variadic
arguments, there is currently no other way to unpack a vector of
arguments into an argument list the way (e.g.) Ruby&amp;#39;s &lt;code&gt;*&lt;/code&gt; prefix does.&lt;/p&gt;

&lt;p&gt;In the future, something like this will probably work&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;args = [];
// ...append arguments to args...
thing.msg(*args);       // Not implemented yet
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;but for now, you&amp;#39;ll need to use &lt;code&gt;sendv&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;args = [];
// ...append arguments to args...
thing.sendv(:msg, args);
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;The Machinery of Objects and Classes&lt;/h2&gt;

&lt;p&gt;Under the hood, the Loom object system is actually (crudely)
&lt;a href=&quot;https://en.wikipedia.org/wiki/Prototype-based_programming&quot;&gt;prototype-based&lt;/a&gt;,
by which I mean that 1) objects have their own method dictionaries and
2) can delegate method lookup to one or more other objects.&lt;/p&gt;

&lt;p&gt;In practice, it isn&amp;#39;t a very &lt;strong&gt;good&lt;/strong&gt; prototype system, but there&amp;#39;s
enough there to use as the basis for a powerful class-based object
system.&lt;/p&gt;

&lt;p&gt;The core idea behind this is that we have a special kind of object
called a &lt;strong&gt;trait&lt;/strong&gt;. Traits are ordinary objects with the usual method
dictionary (and delegate list), but they also have a second method
dictionary/delegate list pair.  (We call these &lt;q&gt;inner&lt;/q&gt; methods and
delegates.)&lt;/p&gt;

&lt;p&gt;If an object has a trait as a delegate, the trait&amp;#39;s &lt;strong&gt;inner&lt;/strong&gt; dictionary
(and inner delegate list) will be used instead of the usual (&lt;q&gt;outer&lt;/q&gt;)
one.&lt;/p&gt;

&lt;p&gt;This gives us the foundation for classes and the rest is just library
code implementing common-sense conventions. In Loom, a class is just a
trait that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Provides the method &lt;code&gt;new&lt;/code&gt; (to create new instances).&lt;/li&gt;
&lt;li&gt; Provides a method named &lt;code&gt;slots&lt;/code&gt; that returns the list of instance
variables.&lt;/li&gt;
&lt;li&gt; Provides the method &lt;code&gt;subclass&lt;/code&gt; to create a subclass.&lt;/li&gt;
&lt;li&gt; Is part of the common class heirarchy rooted at &lt;code&gt;Object&lt;/code&gt;, using its
first inner delegate slot as the superclass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Items 1, 2 and 3 are provided by the metaclass &lt;code&gt;Class&lt;/code&gt;, which serves as
the class of all named classes (including &lt;code&gt;Class&lt;/code&gt; itself) and item 4 is
de-facto enforced by method &lt;code&gt;subclass&lt;/code&gt; since all objects that provide it
are already in the heirarchy.&lt;/p&gt;

&lt;p&gt;Traits also give us mixins (which I call AddonTraits for dumb reasons):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Boopable = AddonTrait.new;
Boopable::boop = { &amp;quot;Booped.&amp;quot;.println };

def BoopableContact = Contact.subclass([], Boopable);

BoopableContact.new(&amp;quot;George Harrison&amp;quot;).boop;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These can be mixed into new classes by passing them to &lt;code&gt;subclass&lt;/code&gt; after
the slot list.&lt;/p&gt;

&lt;h2&gt;Blocks and Control Flow&lt;/h2&gt;

&lt;p&gt;Loom, like Smalltalk, has easy lambdas (called &lt;q&gt;blocks&lt;/q&gt; here&lt;sup id=&quot;fnref4&quot;&gt;&lt;a href=&quot;#fn4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;), and
as in Smalltalk and Lisp, they&amp;#39;re used for flow control.&lt;/p&gt;

&lt;p&gt;(By &lt;q&gt;lambda&lt;/q&gt;, I mean an anonymous function that has access to the
(possibly local) scope in it was defined.)&lt;/p&gt;

&lt;p&gt;You normally define a block with braces, just like method bodies, and
you invoke it with the &lt;code&gt;call&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;blk = {&amp;quot;***block body***&amp;quot;.println};
blk.call();             # &amp;quot;***block body***&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Blocks can (but don&amp;#39;t have to) take arguments and define local
variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;add = {|a, b| |result| result = a + b; result};
add.call(3, 4);         # 7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And they capture their local context:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Thing::counter = {||
    |total| 
    total = 0;
    return { total = total + 1; total }
};

def x = Thing.new.counter;
x.call;               # 1
x.call;               # 2
x.call;               # 3
x.call;               # 4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&amp;#39;re familiar with Lisp, Ruby, or Smalltalk, this is old hat to
you. (If not and I just blew your mind, feel free to take a moment.)&lt;/p&gt;

&lt;p&gt;Loom uses blocks for nearly all flow control. For example, the &lt;code&gt;if&lt;/code&gt;
statement is implemented by adding methods to the Boolean types:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Boolean = Object.subclass([]);
def True = Boolean.new;
def False = Booelan.new;

True::*if = {|body| return body.call()};
False::*if = {|body| return false};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since all boolean operations return &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;, something like
this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a &amp;gt; b .if { &amp;quot;a is bigger!&amp;quot;.println };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;works as expected. If &lt;code&gt;a &amp;gt; b&lt;/code&gt; returns &lt;code&gt;True&lt;/code&gt;, it will invoke &lt;code&gt;True&lt;/code&gt;&amp;#39;s
&lt;code&gt;if&lt;/code&gt; and that will evaluate the block. If it returns &lt;code&gt;False&lt;/code&gt;, it will
instead return &lt;code&gt;False&lt;/code&gt;&amp;#39;s &lt;code&gt;if&lt;/code&gt;, which does not.&lt;/p&gt;

&lt;p&gt;Short-circuited AND and OR operations work in much the same way:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a &amp;gt; b &amp;amp;&amp;amp; { self.is_really_better(a, b) } .if { self.do_thing(a) };
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Aside: the parser will treat one or more blocks following an ordinary
message send as arguments for that message. So the following are
equivalent:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a.b({1}, {2});
a.b({1}) {2};
a.b() {1} {2};
a.b {1} {2};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which can make the code look a bit cleaner.  In the case of the &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;
operator, normal parsing rules apply; there&amp;#39;s an implicit pair of
parents around the first block.)&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;foreach&lt;/code&gt; loop&amp;#39;s equivalent is provided by the &lt;code&gt;Vector&lt;/code&gt; method
&lt;code&gt;each&lt;/code&gt; (by way of a mixin named &lt;code&gt;Enumerable&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[1,2,3,4,5].each{|n| n.str + &amp;quot;,&amp;quot; .print }   # 1,2,3,4,5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also have the usual other map/reduce/etc methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[1,2,3,4,5].map{|n| n*n}                    # [1, 4, 9, 16, 25]
[1,2,3,4,5].select{|n| n*2 &amp;gt; 4}             # [3, 4, 5]
[1,2,3,4,5].inject(0) {|sum, n| sum + n}    # 15
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the &lt;code&gt;for&lt;/code&gt; loop&amp;#39;s equivalent is the same thing, but over an object
(class &lt;code&gt;Range&lt;/code&gt;) that pretends to be an array of increasing integers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1 -&amp;gt; 5.each{|n| n.str + &amp;quot; &amp;quot; .print }
1 2 3 4 5
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the typical &lt;code&gt;while&lt;/code&gt; loop is just as easy. All it needs is... um...&lt;/p&gt;

&lt;p&gt;Okay, fine, &lt;code&gt;while&lt;/code&gt; is a built-in method of &lt;code&gt;Block&lt;/code&gt; written in C++.&lt;/p&gt;

&lt;p&gt;You call it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{n &amp;lt; 5} .while { n = n + 1 ; n.str + &amp;quot; &amp;quot; .print }
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;How Methods Work&lt;/h2&gt;

&lt;p&gt;As mentioned above, the brace-delimited function syntax (&lt;q&gt;{ ... }&lt;/q&gt;) is
syntactic sugar expanded by the parser into a set of message sends. It
makes &lt;strong&gt;some&lt;/strong&gt; sense to think of it as a fancier form of the quoted
array expression.   That is, something like this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{ a + 1; b + 2 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;expands to something a lot like the expansion of&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:[ a + 1, b + 2 ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(This is before we talk about the arguments and local variables, of
course. Also, the parser treats semicolons as separators but will
forgive extras more easily.)&lt;/p&gt;

&lt;p&gt;The missing piece of this is what happens when you quote a Loom message
send:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:( a + 1 )              # a.+(1)
:( a + 1 ).class        # MsgExpr
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#39;s right, there&amp;#39;s a class representing a message send expression. It
looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def MsgExpr = Object.subclass(:[
    receiver,       # The expression to the left of the &amp;quot;.&amp;quot;
    message,        # The message, a symbol
    args            # The vector of argument expressions
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A method body is just an array of these (or symbols, or other objects),
and a trivial Loom interpreter looks something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Evaluator::eval_obj = { | context, obj |
    obj.class == MsgExpr .if { ||
        | receiver, args |
        receiver = self.eval_obj(context, obj.receiver);
        args = args.map{|arg| self.eval_obj(context, arg) };
        return receiver.send(obj.message, args);
    };
    obj.class == Symbol .if { return context.lookup_name(obj) };
    return obj;
};

Evaluator::eval_method_body = { | context, method_body |
    method_body.each{|expr| self.eval_obj(context, expr) };
    return context.lookup(:Self);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are more fiddly little details to it than that, but this is the
core idea.&lt;/p&gt;

&lt;p&gt;If you quote a block definition,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:( {2+3} )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;you&amp;#39;ll get something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ProtoMethod.new([], nil, [], :[2.+(3)], nil).make_block(Here)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which is to say that you&amp;#39;re getting a little bit more than just a list
of expressions. Block (and method) definitions expand into an instance
of class &lt;code&gt;ProtoMethod&lt;/code&gt;, which looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def ProtoMethod = Object.subclass(:[
    args,       # Vector of formal arguments
    restvar,    # nil or the name of the variadic argument list
    locals,     # Vector of local variable names
    body,       # Vector of expressions that make up the method body
    annotation  # nil or a descriptive string intended for error messages
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first three arguments get filled from the argument and local
variables list and the fourth is the actual method body.&lt;/p&gt;

&lt;p&gt;This could be interpreted as a method or block by something like the
&lt;code&gt;Evaluator&lt;/code&gt; example above.  However, in the actual implemention,
methods and blocks are opaque internal C++ structures that are easy to
access from the actual (C++) evaluator.  &lt;code&gt;ProtoMethod&lt;/code&gt; serves as the
intermediate step.  Actual methods are created by a pair of build-in
methods, &lt;code&gt;make_block&lt;/code&gt; and &lt;code&gt;make_method&lt;/code&gt;.  This is analogous to how
Lisp&amp;#39;s &lt;code&gt;lambda&lt;/code&gt; converts several lists into a callable function.&lt;/p&gt;

&lt;p&gt;So there&amp;#39;s nothing stopping you from constructing a
&lt;code&gt;ProtoMethod.new(...)&lt;/code&gt; expression programmatically and turning it into
an executable object.&lt;/p&gt;

&lt;p&gt;(You can also get &lt;strong&gt;just&lt;/strong&gt; the &lt;code&gt;ProtoMethod&lt;/code&gt; by prefixing your Block
declaration with a colon:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:{2+3}          # ProtoMethod([],nil,[],[2.+(3)],nil
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is occasionally useful.)&lt;/p&gt;

&lt;p&gt;There&amp;#39;s one subtle gotcha here, though. Loom requires you to declare
variables before you use them. This is a guard against typo-based bugs
and also makes the scopes of names unambiguous.&lt;/p&gt;

&lt;p&gt;So this method definition will result in an error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def Thing = Object.subclass([])
Thing::bar = { return some_undefined_variable }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But this one &lt;strong&gt;won&amp;#39;t&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Thing::foo = { |a| a .if { return another_undefined_variable } }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The reason for this, if you think about it for a few moments&lt;sup id=&quot;fnref5&quot;&gt;&lt;a href=&quot;#fn5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; is
pretty clear. The inner block expands into an expression like
&lt;code&gt;ProtoMethod.new(...).make_block(...)&lt;/code&gt;. That is, not a function, but an
expression that will &lt;strong&gt;create&lt;/strong&gt; the function. So the method doesn&amp;#39;t
touch any undefined variables at all. It&amp;#39;s only when it gets run and
tries to define the block that it does something wrong. Which is, of
course, far too late for our purposes.&lt;/p&gt;

&lt;p&gt;And because the whole thing is just done with ordinary(ish) objects and
methods, it&amp;#39;s not like I&amp;#39;ll always be able to guarantee the name
correctness of a block or method. So I&amp;#39;ve kind of painted myself into a
corner, haven&amp;#39;t I?&lt;/p&gt;

&lt;p&gt;Well, not really. Every brace expression gets expanded into something
static enough that it&amp;#39;s relatively straightforward to search it for
undefined names&lt;sup id=&quot;fnref6&quot;&gt;&lt;a href=&quot;#fn6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;. So this is what we do.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;re doing something clever with &lt;code&gt;ProtoMethods&lt;/code&gt; like creating
them programmatically, the system (probably) won&amp;#39;t help you, but at
that point, undefined names are the least of your worries. For
ordinary blocks and methods, the Loom will give you a warning
(upgradeable to error) if you get a name wrong.&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;Here&lt;/code&gt;, or How Variable Assignment Works&lt;/h2&gt;

&lt;p&gt;The thing I&amp;#39;ve mostly skirted around so far is how variable assignment
works in Loom. You&amp;#39;ll recall that &amp;lt;reverb&amp;gt;&lt;strong&gt;Everything Is Done
With Message Sends&lt;/strong&gt;&amp;lt;/reverb&amp;gt;. Most things are easy enough to do
that way, but variables aren&amp;#39;t objects so you can&amp;#39;t send them messages.&lt;/p&gt;

&lt;p&gt;In Smalltalk (and Lisp), variable assignment is one of the few things
that still needs to be done by its own top-level thing instead of
calling a method or function. Finding a way to do this was a shower
problem for me for a while, and when I hit on this idea, it was enough
to inspire me to actually build a language around it.&lt;/p&gt;

&lt;p&gt;It goes like this:&lt;/p&gt;

&lt;p&gt;Each context has a local constant named &lt;code&gt;Here&lt;/code&gt; (aliased to &lt;code&gt;here&lt;/code&gt;) that
references the context itself&lt;sup id=&quot;fnref7&quot;&gt;&lt;a href=&quot;#fn7&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;. &lt;code&gt;Here&lt;/code&gt;&amp;#39;s class (&lt;code&gt;Context&lt;/code&gt;) provides
methods to access its names or those of outer scopes according to the
expected scoping rules. The method &lt;code&gt;set&lt;/code&gt; does the latter.&lt;/p&gt;

&lt;p&gt;The parser simply expands conventional variable assignments into
&lt;code&gt;here.set(...)&lt;/code&gt; message sends:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;foo = bar + 1;                  // This...
here.set(:foo, bar + 1);        // ...becomes this.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;here.set&lt;/code&gt; follows the same scoping rules that the evaluator uses when
looking up variables (current block, outer blocks, method, object, and
global) and stores the value in the appropriate namespace and slot.&lt;/p&gt;

&lt;p&gt;As with blocks, this means that you can defeat the compile-time checks
for undefined names if you&amp;#39;re overly clever:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;here.set(&amp;quot;unknown_&amp;quot; + &amp;quot;variable&amp;quot; .intern, 42)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;#39;s fine. The name checking really only cares about likely
accidents, which means the boring infix-style assignment you get from
the syntactic sugar. That&amp;#39;s where the name typos you don&amp;#39;t expect will
come from.&lt;/p&gt;

&lt;p&gt;But having &lt;code&gt;here&lt;/code&gt; as the way to access your local scope gives you all
kinds of extra flexibilty. Consider this little &lt;q&gt;debug printf&lt;/q&gt; method
you can monkeypatch onto &lt;code&gt;Context&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Context::pvar = {|name|
    self.has(name) .if {
        name.str + &amp;quot;=&amp;quot; + (self.get(name).str) .println
    };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now if you want to print a variable, you can just do&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Bar::do_thing = {
    // ...
    here.pvar(:a);
    // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you&amp;#39;ll get a nicely-formatted message.&lt;/p&gt;

&lt;h2&gt;Odds and Ends&lt;/h2&gt;

&lt;h3&gt;How &lt;code&gt;return&lt;/code&gt; works&lt;/h3&gt;

&lt;p&gt;The final bit of syntactic magic is the &lt;code&gt;return&lt;/code&gt; statement. Like
everything else, it&amp;#39;s syntactic sugar wrapping a message send.
Specifically, it invokes &lt;code&gt;Context::return&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s a typical method with a return statement:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Bar::thing = { |a| return a + 1 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;return a + 1&lt;/code&gt; part expands to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;here.method_scope.return(a + 1);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;method_scope&lt;/code&gt; returns the &lt;code&gt;Context&lt;/code&gt; belonging to the current method
call&lt;sup id=&quot;fnref8&quot;&gt;&lt;a href=&quot;#fn8&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;. This is important because we expect &lt;code&gt;return&lt;/code&gt; to operate at the
method level:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ContactInfo::dial = {
    self.location.time_of_day &amp;lt; (Time.noon) .if { return nil };
    return self.really_dial;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is, we expect the &lt;code&gt;return&lt;/code&gt; after the &lt;code&gt;if&lt;/code&gt; to cause &lt;code&gt;dial&lt;/code&gt; to return
before the next expression (calling &lt;code&gt;really_dial&lt;/code&gt;). If &lt;code&gt;return
nil&lt;/code&gt; had expanded to &lt;code&gt;here.return(nil)&lt;/code&gt;, it would only have exited from
the block itself and not the method.&lt;/p&gt;

&lt;p&gt;This mechanism can be (ab)used in clever ways. For example, this method&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Thing::quux = {
    {
        {
            Here.outer.return(42);
            return &amp;quot;nope&amp;quot;;        // skipped
        }.call;
        return &amp;quot;also nope&amp;quot;;       // skipped
    }.call;
    return &amp;quot;Yup&amp;quot;;                 // run
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;will return the string &lt;code&gt;&amp;quot;Yup&lt;/code&gt; because the innermost return will cause
the outer two blocks to also exit and let control flow fall to the next
statement.&lt;/p&gt;

&lt;p&gt;Doing stuff like this is generally a bad idea, but it illustrates how
powerful &lt;code&gt;Context::return&lt;/code&gt; can be. Future versions of Loom may add extra
control statements (e.g. &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt;) built on this stuff.&lt;/p&gt;

&lt;h3&gt;Exceptions and Ensure&lt;/h3&gt;

&lt;p&gt;Loom also has exceptions. They got added late to the process, just
because it made it so much easier to write tests for failing conditions.&lt;/p&gt;

&lt;p&gt;Initially, Loom had a &lt;code&gt;Context&lt;/code&gt; method named &lt;code&gt;fail&lt;/code&gt;, which quit the
program with a message. That worked well enough for a while, but the
tests got increasingly awkward so I added catchable exceptions.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{   
    here.throw(&amp;quot;Some error&amp;quot;)
}.catch(String) {|e| 
    &amp;quot;Caught exception &amp;#39;&amp;quot; + e + &amp;quot;&amp;#39;&amp;quot; .println;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And it does pretty much what you expect. &lt;code&gt;Block::catch&lt;/code&gt; is like &lt;code&gt;call&lt;/code&gt;,
except that if &lt;code&gt;Context::throw&lt;/code&gt; is called with an object whose class
matches&lt;sup id=&quot;fnref9&quot;&gt;&lt;a href=&quot;#fn9&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; &lt;code&gt;catch&lt;/code&gt;&amp;#39;s first argument, calls its second argument with it
and execution continues from there on.&lt;/p&gt;

&lt;p&gt;It probably would have been possible to write this in pure Loom using
&lt;code&gt;Context::return&lt;/code&gt;, but currently it&amp;#39;s just two native C++ functions with
about 25 lines of code.&lt;/p&gt;

&lt;p&gt;In an earlier draft of this post, the next couple of paragraphs talked
about how this exception system was pretty weak overall. The underlying
problem is that there&amp;#39;s no way to guarantee that cleanup code will run
after an exception the way Java does with &lt;code&gt;finally&lt;/code&gt; or Ruby does with
&lt;code&gt;ensure&lt;/code&gt;, leading to all kinds of hard-to-track-down errors.&lt;/p&gt;

&lt;p&gt;But then, I asked myself how hard it would &lt;strong&gt;really&lt;/strong&gt; be to just fix
that rather than document the failings. So I tried it, and it took maybe
half a day to implement.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s an example of the feature:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    fh = File.new(filename);
    self.process(fh);
}.callAndEnsure {
    fh.close();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The block argument (in this case, containing &lt;code&gt;fh.close()&lt;/code&gt;) is
&lt;strong&gt;always&lt;/strong&gt; called after the receiving block exits, regardless of
how. It can throw an exception or do a return or just run to the end.&lt;/p&gt;

&lt;p&gt;You can also combine it with exception catching, as one does:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    fh = File.new(filename);
    self.process(fh);
}.catchAndEnsure(ProcessingException) { |e|
    return nil;
} {
    fh.close();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Both of these methods are written in pure Loom, by the way. The
undelying machinery is provided by built-in method &lt;code&gt;Context::ensure&lt;/code&gt;.
This takes a block and evaluates it just before the context returns.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the source code for &lt;code&gt;catchAndEnsure&lt;/code&gt; to illustrate this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Block::catchAndEnsure = {|klass, handler, ensure_block|
    here.ensure(ensure_block);
    return self.catch(klass, handler);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The ensure block gets attached to the method&amp;#39;s &lt;code&gt;here&lt;/code&gt; instead of the
call to &lt;code&gt;self&lt;/code&gt;, but that&amp;#39;s good enough. After &lt;code&gt;self.catch(...)&lt;/code&gt; exits,
&lt;code&gt;here&lt;/code&gt; will also always return so &lt;code&gt;ensure_block&lt;/code&gt; will also be evaluated.&lt;/p&gt;

&lt;h3&gt;Bypassing Overridden Methods (i.e. &lt;q&gt;super&lt;/q&gt;)&lt;/h3&gt;

&lt;p&gt;I ended up writing a lot of Loom code before the first time I needed to
be able to call a superclass&amp;#39;s version of a method the current object
had overridden. Which surprised me; I&amp;#39;d assumed that I&amp;#39;d need it much
sooner than that&lt;sup id=&quot;fnref10&quot;&gt;&lt;a href=&quot;#fn10&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;But I &lt;strong&gt;did&lt;/strong&gt; need it, and it was unexpectedly tricky to figure out how
to do it without any magic.&lt;/p&gt;

&lt;p&gt;tl; dr, I ended up adding it &lt;code&gt;Context&lt;/code&gt; as a method named &lt;code&gt;super_send&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This works just like &lt;code&gt;self.send&lt;/code&gt; but the method search starts at the
superclass of the class that defined this method. (&lt;strong&gt;Not&lt;/strong&gt; &lt;code&gt;self&lt;/code&gt;; it&amp;#39;s
possible that it&amp;#39;s already inherited this method, so the &lt;strong&gt;method&lt;/strong&gt;
determines the starting point.)&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Thing::blatt = {|x| return here.super_send(:blatt, x); }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, symmetrically with &lt;code&gt;Object::send&lt;/code&gt;, there&amp;#39;s a &lt;code&gt;sendv&lt;/code&gt; version:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Thing::blatt = {|x| return here.super_sendv(:blatt, [x]); }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The reason it belongs to &lt;code&gt;Context&lt;/code&gt; is because at the time of the
&lt;code&gt;super_send&lt;/code&gt; call, &lt;code&gt;here&lt;/code&gt; is the only well-known object that knows both
&lt;code&gt;self&lt;/code&gt; and current method.&lt;/p&gt;

&lt;h2&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Loom is the first language I&amp;#39;ve designed that I actually want to use.&lt;/p&gt;

&lt;p&gt;Most of my experiments in language design are successful in that they
produce a result, but that result has usually been, &lt;q&gt;That wasn't a good
idea after all.&lt;/q&gt; Loom didn&amp;#39;t do that.&lt;/p&gt;

&lt;p&gt;The tooling is awful, libraries are nonexistant, and the whole thing
runs at geological speeds. And yet, it&amp;#39;s &lt;strong&gt;fun&lt;/strong&gt; to write Loom code.
Writing runtime code was almost always easier in Loom than in C++. This
despite the fact that I have an &lt;strong&gt;extremely&lt;/strong&gt; good C++ toolchain with
astoundingly good debugger support.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s been fun even when I did really complex things. Figuring out if a
Block uses an undefined name was difficult and required a lot of thought
and iterative design, but doing that in Loom was not only possible but
&lt;strong&gt;easier&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So that&amp;#39;s how I&amp;#39;ll end it. Loom doesn&amp;#39;t suck. I&amp;#39;m as surprised by this
as you are.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;

&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;If you&amp;#39;re unfamiliar with the Smalltalk concept of &lt;q&gt;sending a
message to an object&lt;/q&gt;, just mentally replace the term with &lt;q&gt;calling
a method&lt;/q&gt;. That&amp;#39;s close enough for our purposes.&amp;nbsp;&lt;a href=&quot;#fnref1&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn2&quot;&gt;
&lt;p&gt;Calling it a parser is perhaps overly generous, but it&amp;#39;s the thing
that turns text into internal data structures, so there we go.&amp;nbsp;&lt;a href=&quot;#fnref2&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn3&quot;&gt;
&lt;p&gt;I had planned to add brackets and full BEDMAS infix evaluation
order rules, but I found that just this and the other little bits of
syntax were enough.&amp;nbsp;&lt;a href=&quot;#fnref3&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn4&quot;&gt;
&lt;p&gt;This term was also stolen from Smalltalk.&amp;nbsp;&lt;a href=&quot;#fnref4&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn5&quot;&gt;
&lt;p&gt;This is &lt;strong&gt;totally&lt;/strong&gt; something I saw coming from the start and
didn&amp;#39;t catch me by surprise long after the basic Loom system was up
and running.&amp;nbsp;&lt;a href=&quot;#fnref5&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn6&quot;&gt;
&lt;p&gt;Fun fact: the code that does this is written &lt;strong&gt;in Loom itself&lt;/strong&gt;.
It also serves as an optimizer because it will evaluate the
&lt;code&gt;ProtoMethod.new(...)&lt;/code&gt; expressions ahead of time.&amp;nbsp;&lt;a href=&quot;#fnref6&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn7&quot;&gt;
&lt;p&gt;Smalltalk also has &lt;code&gt;Here&lt;/code&gt; (named &lt;code&gt;thisContext&lt;/code&gt;, though) but
doesn&amp;#39;t take the next step of using it for variable assignment.&amp;nbsp;&lt;a href=&quot;#fnref7&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn8&quot;&gt;
&lt;p&gt;Or nil, if there isn&amp;#39;t one. That&amp;#39;s not really possible on the
current C++ implementation, though, since each input expression gets
turned into its own wierd mutant unnamed method.&amp;nbsp;&lt;a href=&quot;#fnref8&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn9&quot;&gt;
&lt;p&gt;By which I mean, is an instance of the class passed to &lt;code&gt;catch&lt;/code&gt; or
one of its subclasses.&amp;nbsp;&lt;a href=&quot;#fnref9&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn10&quot;&gt;
&lt;p&gt;You would think that decades of writing OOP code would have been
the hint, but nope.&amp;nbsp;&lt;a href=&quot;#fnref10&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
</description>
      <pubDate>Sun, 19 Nov 2023 21:35:40 -0000</pubDate>
      <guid>gqr0ks77yz</guid>
      <dc:date>2023-11-19T21:35:40Z</dc:date>
    </item>
    <item>
      <title>Low-effort Retrocomputing</title>
      <link>http://www.blit.ca/blog/ghewkoqmq9/Low-effort_Retrocomputing.html</link>
      <description>&lt;p&gt;So the other day, I wondered if anyone had put up pre-installed disk
images for any of the really old Linux distros.  I found installation
media at
&lt;a href=&quot;https://ia801309.us.archive.org/6/items/Slackware_Linux_3.0_Walnut_Creek_October_1995/&quot;&gt;archive.org&lt;/a&gt;
and
&lt;a href=&quot;https://boxes-of-tat.blogspot.com/2021/08/slackware-linux-30-on-qemu.html&quot;&gt;this blog post&lt;/a&gt;.
with (excellent) instructions on how to do it, but nobody had done the
work (so I wouldn&amp;#39;t have to) and put it up for download.&lt;/p&gt;

&lt;p&gt;So I took a run at it and installed Slackware 3.0 (from 1995) on a
QEMU disk image:&lt;/p&gt;

&lt;p&gt;&lt;img width=100% title=&quot;Screenshot of the Slackware 3.0 disk configurator&quot; alt=&quot;Screenshot of the Slackware 3.0 disk configurator&quot; src=&quot;ghewkoqmq9/slackware-app-selector.png&quot;&gt;    
&lt;/p&gt;

&lt;p&gt;You can download it &lt;a href=&quot;http://blit.ca/downloads/slackware3_qemu.tar.xz&quot;&gt;here&lt;/a&gt;.
The archive&amp;#39;s sha256 hash is&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;28be1e75f8c5b8e9338f18589549ebc871e6daae3d4a7433826684d0cae446d1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Please be considerate of my bandwidth.)&lt;/p&gt;

&lt;p&gt;The image has two accounts: &lt;code&gt;root&lt;/code&gt; and a user account named &lt;code&gt;bob&lt;/code&gt;;
both have the password &lt;q&gt;slack&lt;/q&gt;.  It boots into X11 but you can get to
a text console by pressing &lt;code&gt;Ctrl+Alt+1&lt;/code&gt; if you need to.  Note that the
console&amp;#39;s termcap seems to be a bit messed up.&lt;/p&gt;

&lt;p&gt;Networking works, but there&amp;#39;s no web browser or &lt;code&gt;ssh&lt;/code&gt; client.  There&amp;#39;s
a C compiler though (I installed &lt;strong&gt;everything&lt;/strong&gt;) so you should be able
to build period-appropriate ssh from sources if you need to.  There
are also Linux builds of Netscape 3 on the &amp;#39;net, although I have no
idea if they&amp;#39;ll run on Slackware.&lt;/p&gt;

&lt;p&gt;Configuring X took some hand-fiddling. You can see my work in
&lt;code&gt;/etc/XF86Config&lt;/code&gt; and compare it to the original generated config file
&lt;code&gt;/etc/XF86Config.orig&lt;/code&gt; if you want.&lt;/p&gt;

&lt;p&gt;Anyway, feel free to download and play with it if you&amp;#39;re curious or
nostalgic or want to do pre-1995-tech dev jam.&lt;/p&gt;
</description>
      <pubDate>Thu, 19 Jan 2023 16:46:42 -0000</pubDate>
      <guid>ghewkoqmq9</guid>
      <dc:date>2023-01-19T16:46:42Z</dc:date>
    </item>
    <item>
      <title>Your Sucks Programming Language Favourite</title>
      <link>http://www.blit.ca/blog/g05njdhlul/Your_Sucks_Programming_Language_Favourite.html</link>
      <description>&lt;p&gt;Much to my chagrin, I&amp;#39;ve found myself lately becoming a defender of
C++.  People who a) know me and b) appreciate irony should feel free
to smirk right about now.&lt;/p&gt;

&lt;p&gt;To be fair, modern C++ has improved significantly, reaching rarified
hights of not-badness only dreamed of fifteen years ago.  But that&amp;#39;s
kind of beside the point.  When you choose a programming language for
a project, the quality of the language itself is often less important
than external stuff; the quality of available implementations, tools,
research, etc.&lt;/p&gt;

&lt;p&gt;If I&amp;#39;m going to bet my (hypothetical) business on investing a zillion
dollars to write a program that I can then sell, I want to know that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The development tools aren&amp;#39;t going to rot or disappear because the
vendor lost interest (e.g. &lt;a href=&quot;https://en.wikipedia.org/wiki/Visual_Basic#2000s&quot;&gt;Visual Basic&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;I&amp;#39;ll be able to hire skilled developers whenever I need to.&lt;/li&gt;
&lt;li&gt;Good quality tools, books, training, etc. will all be available
when I need them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(And as a developer, I want to bet my non-hypothetical livelihood on
developing the skills that are most likely to keep me employed.
Being a really badass Haskell programmer doesn&amp;#39;t really do much for my
job search&lt;sup id=&quot;fnref1&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.)&lt;/p&gt;

&lt;p&gt;So let&amp;#39;s concede that Rust (for example) is a better language than C++.
C++ will still be a better choice for most commercial ventures in that
space because it has:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multiple high-quality implementations, two of which are FOSS&lt;sup id=&quot;fnref2&quot;&gt;&lt;a href=&quot;#fn2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;A huge selection of high-quality third-party tools&lt;/li&gt;
&lt;li&gt;An enormous community of developers with whom you can exchange
knowledge&lt;/li&gt;
&lt;li&gt;A literal half-century of concerted research on how to use it
effectively&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;C++ sucks in a variety of ways but we know exactly how it sucks and
how to work around it.  Rust&amp;#39;s suckage is still unknown, and I want
the thing that keeps me from being homeless&lt;sup id=&quot;fnref3&quot;&gt;&lt;a href=&quot;#fn3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; to have a really good
track record.&lt;/p&gt;

&lt;p&gt;And this principle applies to Scala-vs-Java, Zig-vs-C,
Haskell-vs-anything, anything-please-anything-vs-PHP or any other
language debate.  $FAVORITE_LANGUAGE may be a better language than
$CHOSEN_LANGUAGE but that doesn&amp;#39;t mean it&amp;#39;s going to get the job
done better, faster, cheaper or more reliably.  All of that depends on
the entirety of the language&amp;#39;s ecosystem.&lt;/p&gt;

&lt;p&gt;Note that I&amp;#39;m &lt;strong&gt;not&lt;/strong&gt; saying &lt;q&gt;don't use $FAVORITE_LANGUAGE.&lt;/q&gt;  Just
be aware of what&amp;#39;s riding on that decision.  For a hobby project or an
in-house tool that took a month to write, it&amp;#39;s going to be fine.  But
for the hundred person-year project the business depends on?  I mean,
I&amp;#39;d really like $FAVORITE_LANGUAGE to be viable in ten years but I&amp;#39;m
not going to bet the mortgage on it.&lt;/p&gt;

&lt;p&gt;Also, you &lt;strong&gt;should&lt;/strong&gt; go out and learn all kinds of programming
languages--especially wierd ones that will never fly in
Industry--because it will make you a better programmer.  I got a
&lt;strong&gt;lot&lt;/strong&gt; of benefit as a C programmer from asking myself, &lt;q&gt;How would I
do this in Smalltalk?&lt;/q&gt;&lt;/p&gt;

&lt;p&gt;I&amp;#39;m a programming language nerd.  I&amp;#39;ve spent a &lt;strong&gt;lot&lt;/strong&gt; of time
thinking about how languages work and how they make people think about
programming.  I learn new languages for fun and I&amp;#39;ve
&lt;a href=&quot;http://www.blit.ca/blog/fdey966ldd/Sic__Yet_Another_Mediocre_Small_Lisp_Dialect.html&quot;&gt;designed&lt;/a&gt;
and &lt;a href=&quot;http://blit.ca/deck.html&quot;&gt;implemented&lt;/a&gt; several.  So I absolutely
get the desire to use better languages and the frustration of having
to deal with the broken status quo.  In a perfect world, we&amp;#39;d all be
using Smalltalk.&lt;/p&gt;

&lt;p&gt;Unfortunately, our world is fallen and so C++ is a necessary evil.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;

&lt;li id=&quot;fn1&quot;&gt;
&lt;p&gt;Okay, that&amp;#39;s an exaggeration.  A good hiring process will
  recognize that Haskell skills are often transferable to whatever the
  company is using.  Unfortunately, a lot of otherwise-fine employers
  have terrible hiring processes and will reject any résumé not listing
  the exact version of their preferred web framework.  As those
  companies have money they will exchange for relatively pleasant work,
  I would like to retain the option of working there.&amp;nbsp;&lt;a href=&quot;#fnref1&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn2&quot;&gt;
&lt;p&gt;&lt;q&gt;But if $FAVORITE_LANGUAGE is FOSS, that means it will be
  available forever!&lt;/q&gt;  No, not really.  If nobody else is working
  on it, you&amp;#39;ll find yourself having to maintain the toolchain by
  yourself.  At that point, it&amp;#39;s almost always easier to just
  rewrite your program in something else.&amp;nbsp;&lt;a href=&quot;#fnref2&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;li id=&quot;fn3&quot;&gt;
&lt;p&gt;Yeah, yeah, I know; the real problem is Capitalism.&amp;nbsp;&lt;a href=&quot;#fnref3&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;
&lt;/div&gt;
</description>
      <pubDate>Sun, 04 Jul 2021 18:09:16 -0000</pubDate>
      <guid>g05njdhlul</guid>
      <dc:date>2021-07-04T18:09:16Z</dc:date>
    </item>
    <item>
      <title>Getting the Singleton Class of a BasicObject in Ruby</title>
      <link>http://www.blit.ca/blog/fyd7mrwuym/Getting_the_Singleton_Class_of_a_BasicObject_in_Ruby.html</link>
      <description>&lt;p&gt;Ruby objects provide the method &lt;code&gt;singleton_class&lt;/code&gt; which returns the
object&amp;#39;s singleton class.  Unfortunately, &lt;code&gt;BasicObject&lt;/code&gt; doesn&amp;#39;t have
this because it&amp;#39;s &lt;code&gt;Object&lt;/code&gt;&amp;#39;s superclass.  So to get it, we need to be
somewhat clever.&lt;/p&gt;

&lt;p&gt;And having spent &lt;strong&gt;way&lt;/strong&gt; too much time figuring out how to do this, I&amp;#39;m
writing it here so a) that I don&amp;#39;t lose it again and b) so that others
will have less trouble than me.  (I&amp;#39;m not on Medium so, um, hello from
the fourth page of your Google search results.)&lt;/p&gt;

&lt;h2&gt;TL; DR, How do I do it?&lt;/h2&gt;

&lt;p&gt;In an instance, you&amp;#39;d do something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;obj = BasicObject.new
obj.instance_exec(obj) {
  class &amp;lt;&amp;lt; self
    lself = self
    self.define_method(:my_singleton_class) { lself }
  end
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice how I copy &lt;code&gt;self&lt;/code&gt; to &lt;code&gt;lself&lt;/code&gt; on line 4. That&amp;#39;s because &lt;code&gt;self&lt;/code&gt;
will have changed when the method is called but the block that forms
the body of &lt;code&gt;my_singleton_class&lt;/code&gt; captures the local variable.&lt;/p&gt;

&lt;p&gt;Also: this won&amp;#39;t work on Ruby versions from sometime before 2.7
because &lt;code&gt;define_method&lt;/code&gt; is private before then; see your version&amp;#39;s
&lt;code&gt;Module&lt;/code&gt; documentation for &lt;code&gt;define_method&lt;/code&gt; for a hacky workaround if
it&amp;#39;s too old.&lt;/p&gt;

&lt;p&gt;Doing this with a &lt;code&gt;BasicObject&lt;/code&gt; subclass is even simpler:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Thingy &amp;lt; BasicObject
  def my_singleton_class
    class &amp;lt;&amp;lt; self
      return self
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;What&amp;#39;s it good for?&lt;/h2&gt;

&lt;p&gt;Any case where you want an object to handle a method call by doing
something other than call a method.  For example, a DSL or a proxy
object that forwards the call to something else.&lt;/p&gt;

&lt;p&gt;Typically, you&amp;#39;d create a class with no methods, then implement
&lt;code&gt;method_missing&lt;/code&gt; to catch the failing method lookups and do the right
thing with them.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Proxy
  def initialize(target) @target = target;   end
  def method_missing(name, args)
    log &amp;quot;Called #{name} with #{args}&amp;quot;
    return @target.send(name, args)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;BasicObject&lt;/code&gt; is the ideal base class for this because it has very few
methods but if that&amp;#39;s not enough&amp;#x2013;if you need to get rid of those few
as well&amp;#x2013;you can always override (most of) them with a method that
calls &lt;code&gt;method_missing&lt;/code&gt; directly.  This is straightforward when
creating a subclass but there are times when it&amp;#39;s necessary or easier
to add methods to the object instead, and for that you need to get the
singleton class.&lt;/p&gt;

&lt;p&gt;In my case, I&amp;#39;m writing a DSL where every method whose name starts
with a letter is valid; this means they all need to turn into calls to
&lt;code&gt;method_missing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(Handling the case where the user uses &lt;code&gt;method_missing&lt;/code&gt; as a name in
the DSL is left as an exercise to the reader.)&lt;/p&gt;

&lt;h2&gt;What&amp;#39;s a singleton class anyway?&lt;/h2&gt;

&lt;p&gt;So normally in OOP, an object is an instance of a class and this is
the case with Ruby as well:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[]                          # =&amp;gt; []
[].class                    # =&amp;gt; Array
[].class.class              # =&amp;gt; Class
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But, when Ruby creates an object from a class, it also first creates
another anonymous class called the &lt;code&gt;singleton class&lt;/code&gt;.  This gets
inserted in the new object&amp;#39;s inheritance heirarchy: that is, the
singleton class becomes a subclass of the new object&amp;#39;s class and the
object becomes an instance of the singleton instead of the original
class.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x = []                          # =&amp;gt; []
x.class                         # =&amp;gt; Array
x.singleton_class               # =&amp;gt; #&amp;lt;Class:#&amp;lt;Array:0x00007fbc862d41b0&amp;gt;&amp;gt;
x.singleton_class.superclass    # =&amp;gt; Array
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is how you can add methods to individual Ruby objects: you&amp;#39;re
actually defining them in the object&amp;#39;s singleton class.&lt;/p&gt;

&lt;p&gt;Fun fact: singleton classes are also objects and thus have their own
singleton classes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;x.singleton_class
    # =&amp;gt; #&amp;lt;Class:#&amp;lt;Array:0x00007fbc869b0060&amp;gt;&amp;gt;
x.singleton_class.singleton_class
    # =&amp;gt; #&amp;lt;Class:#&amp;lt;Class:#&amp;lt;Array:0x00007fbc869b0060&amp;gt;&amp;gt;&amp;gt;
x.singleton_class.singleton_class.singleton_class
    # =&amp;gt; #&amp;lt;Class:#&amp;lt;Class:#&amp;lt;Class:#&amp;lt;Array:0x00007fbc869b0060&amp;gt;&amp;gt;&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This can go as deeply as you want it to.&lt;/p&gt;

&lt;p&gt;The reason Ruby doesn&amp;#39;t immediately fill up all available RAM with
singleton classes and then die is because they are not created until
the first time a program uses them.  As a result, most objects don&amp;#39;t
have singleton classes at all.&lt;/p&gt;

&lt;h2&gt;Isn&amp;#39;t this whole singleton class thing kind of overkill?&lt;/h2&gt;

&lt;p&gt;Not really.&lt;/p&gt;

&lt;p&gt;See, Ruby is a language where everything is an object (in the OOP
sense of the term), and so this means that classes are also objects.
But since all objects have classes, that means each class is also an
instance of a class.  And so is that class.  And this is if we ignore
the singleton classes, which we are for the moment.&lt;/p&gt;

&lt;p&gt;So how does this end?  Well, it&amp;#39;s pretty boring actually.  Each class
is an instance of the class named &lt;code&gt;Class&lt;/code&gt;, &lt;em&gt;including&lt;/em&gt; &lt;code&gt;Class&lt;/code&gt;
itself.  &lt;code&gt;Class&lt;/code&gt; is an instance of itself and that&amp;#39;s all we really
need.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[]                          # =&amp;gt; []
[].class                    # =&amp;gt; Array
[].class.class              # =&amp;gt; Class
[].class.class.class        # =&amp;gt; Class
[].class.class.class.class  # =&amp;gt; Class
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But wait! How do we do class methods or class instance variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Thing
  def self.instance
    @instance = Thing.new unless @instance
    return @instance
  end
  # ...etc...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In Smalltalk, this gets done by giving each class object its own
distinct class (the &lt;q&gt;metaclass&lt;/q&gt;) to hold the methods and variable
declarations.  They are unnamed but you can get it with the &lt;code&gt;class&lt;/code&gt;
method just like Ruby.  The metaclass&amp;#39;s inheritance tree mirrors the
class&amp;#39;s tree (i.e. if &lt;code&gt;Item&lt;/code&gt; is derived from &lt;code&gt;Thing&lt;/code&gt;, then
&lt;code&gt;Thing.class&lt;/code&gt; is derived from &lt;code&gt;Item.class&lt;/code&gt;) with class &lt;code&gt;Class&lt;/code&gt; as the
abstract base class of the heirarchy.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;t class.                                =&amp;gt; Thing
t class superclass.                     =&amp;gt; Object
t class superclass superclass.          =&amp;gt; nil

t class class.                          =&amp;gt; Unnamed class (&amp;#39;Thing class&amp;#39;)
t class class superclass.               =&amp;gt; Unnamed class (&amp;#39;Object class&amp;#39;)
t class class superclass superclass.    =&amp;gt; Class
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All metaclasses are instances of the class &lt;code&gt;Metaclass&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;t class.                                =&amp;gt; Thing
t class class.                          =&amp;gt; Unnamed class (&amp;#39;Thing class&amp;#39;)
t class class class.                    =&amp;gt; Metaclass
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This includes &lt;code&gt;Metaclass&lt;/code&gt; itself, which is how the loop closes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Metaclass class                         =&amp;gt; &amp;#39;Metaclass class&amp;#39;
Metaclass class class                   =&amp;gt; Metaclass
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Disclaimer: I&amp;#39;ve somewhat simplified the above.  I also haven&amp;#39;t run
it.)&lt;/p&gt;

&lt;p&gt;In Ruby, each &lt;code&gt;Class&lt;/code&gt; instance (i.e. class) has a singleton class that
holds the class methods and variables.  That is, singleton classes
serve as metaclasses.  The nice thing about this is that it&amp;#39;s a
generalization of what Smalltalk does for classes, and it gives you
instance methods for free.&lt;/p&gt;

&lt;p&gt;This is not to say that it&amp;#39;s necessarily a better way than
Smalltalk&amp;#39;s. There are advantages and disadvantages to each approach
but I&amp;#39;m far too lazy to write about them here.&lt;/p&gt;
</description>
      <pubDate>Fri, 07 May 2021 01:57:49 -0000</pubDate>
      <guid>fyd7mrwuym</guid>
      <dc:date>2021-05-07T01:57:49Z</dc:date>
    </item>
    <dc:date>2024-10-20T14:20:43-04:00</dc:date>
  </channel>
</rss>