Files
wren/classes.html
2015-04-25 08:50:08 -07:00

383 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Classes Wren</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<link href='//fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro:400|Lato:400|Sanchez:400italic,400' rel='stylesheet' type='text/css'>
<!-- Tell mobile browsers we're optimized for them and they don't need to crop
the viewport. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
</head>
<body id="top">
<header>
<div class="page">
<div class="main-column">
<h1><a href="./">wren</a></h1>
<h2>a classy little scripting language</h2>
</div>
</div>
</header>
<div class="page">
<nav>
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
</ul>
<section>
<h2>language</h2>
<ul>
<li><a href="syntax.html">Syntax</a></li>
<li><a href="expressions.html">Expressions</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="control-flow.html">Control Flow</a></li>
<li><a href="error-handling.html">Error Handling</a></li>
<li><a href="modules.html">Modules</a></li>
</ul>
</section>
<section>
<h2>types</h2>
<ul>
<li><a href="values.html">Values</a></li>
<li><a href="classes.html">Classes</a></li>
<li><a href="fibers.html">Fibers</a></li>
<li><a href="functions.html">Functions</a></li>
<li><a href="lists.html">Lists</a></li>
<li><a href="maps.html">Maps</a></li>
</ul>
</section>
<section>
<h2>reference</h2>
<ul>
<li><a href="core">Core Library</a></li>
<li><a href="embedding-api.html">Embedding API</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="community.html">Community</a></li>
<li><a href="contributing.html">Contributing</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
</ul>
</section>
</nav>
<main>
<h1>Classes</h1>
<p>Every value in Wren is an object, and every object is an instance of a class.
Even <code>true</code> and <code>false</code> are full-featured objects&mdash;instances of the <code>Bool</code>
class.</p>
<p>Classes contain both <em>behavior</em> and <em>state</em>. Behavior is defined in <em>methods</em>
which are stored in the class. State is defined in <em>fields</em>, whose values are
stored in each instance.</p>
<h2>Defining a class <a href="#defining-a-class" name="defining-a-class" class="header-anchor">#</a></h2>
<p>Classes are created using the <code>class</code> keyword, unsurprisingly:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{}</span>
</pre></div>
<p>This creates a class named <code>Unicorn</code> with no methods or fields.</p>
<h2>Methods <a href="#methods" name="methods" class="header-anchor">#</a></h2>
<p>To let our unicorn do stuff, we need to give it methods.</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="n">prance</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;The unicorn prances in a fancy manner!&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>This defines a <code>prance</code> method that takes no arguments. To support parameters,
add a parenthesized parameter list after the method's name:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="n">prance</span><span class="p">(</span><span class="n">where</span><span class="p">,</span> <span class="n">when</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;The unicorn prances in &quot;</span> <span class="o">+</span> <span class="n">where</span> <span class="o">+</span> <span class="s2">&quot; at &quot;</span> <span class="o">+</span> <span class="n">when</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<h3>Signature <a href="#signature" name="signature" class="header-anchor">#</a></h3>
<p>Unlike most other dynamically-typed languages, in Wren you can have multiple
methods in a class with the same name, as long as they have a different
parameter <em>signature</em>. In technical terms, you can <em>overload by arity</em>. So this
class is fine:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="n">prance</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;The unicorn prances in a fancy manner!&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">prance</span><span class="p">(</span><span class="n">where</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;The unicorn prances in &quot;</span> <span class="o">+</span> <span class="n">where</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">prance</span><span class="p">(</span><span class="n">where</span><span class="p">,</span> <span class="n">when</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;The unicorn prances in &quot;</span> <span class="o">+</span> <span class="n">where</span> <span class="o">+</span> <span class="s2">&quot; at &quot;</span> <span class="o">+</span> <span class="n">when</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>And you can call each of the methods like so:</p>
<div class="codehilite"><pre><span class="kd">var</span> <span class="n">unicorn</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Unicorn</span>
<span class="n">unicorn</span><span class="p">.</span><span class="n">prance</span>
<span class="n">unicorn</span><span class="p">.</span><span class="n">prance</span><span class="p">(</span><span class="s2">&quot;Antwerp&quot;</span><span class="p">)</span>
<span class="n">unicorn</span><span class="p">.</span><span class="n">prance</span><span class="p">(</span><span class="s2">&quot;Brussels&quot;</span><span class="p">,</span> <span class="s2">&quot;high noon&quot;</span><span class="p">)</span>
</pre></div>
<p>The number of arguments provided at the callsite determines which method is
chosen.</p>
<p>It's often natural to have the same conceptual operation work with different
sets of arguments. In other languages, you'd define a single method for the
operation and have to check for "undefined" or missing arguments. Wren just
treats them as different methods that you can implement separately.</p>
<p>Signature is a bit more than just arity. It also lets you distinguish between a
method that takes an <em>empty</em> argument list (<code>()</code>) and no argument list at all:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Confusing</span> <span class="p">{</span>
<span class="n">method</span> <span class="p">{</span> <span class="s2">&quot;no argument list&quot;</span> <span class="p">}</span>
<span class="n">method</span><span class="p">()</span> <span class="p">{</span> <span class="s2">&quot;empty argument list&quot;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="n">confusing</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Confusing</span>
<span class="n">confusing</span><span class="p">.</span><span class="n">method</span> <span class="c1">// &quot;no argument list&quot;.</span>
<span class="n">confusing</span><span class="p">.</span><span class="n">method</span><span class="p">()</span> <span class="c1">// &quot;empty argument list&quot;.</span>
</pre></div>
<p>Like the example says, having two methods that differ just by an empty set of
parentheses is pretty confusing. That's not what this is for. It's mainly so
you can define methods that don't take any arguments but look "method-like".</p>
<p>Methods that don't need arguments and don't modify the underlying object tend
to omit the parentheses. These are "getters" and usually access a property of
an object, or produce a new object from it:</p>
<div class="codehilite"><pre><span class="s2">&quot;string&quot;</span><span class="p">.</span><span class="n">count</span>
<span class="p">(</span><span class="m">1.</span><span class="p">.</span><span class="m">3</span><span class="p">).</span><span class="n">min</span>
<span class="m">0.123</span><span class="p">.</span><span class="n">sin</span>
</pre></div>
<p>Other methods do change the object, and it's helpful to draw attention to that:</p>
<div class="codehilite"><pre><span class="n">list</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
</pre></div>
<p>Since the parentheses are part of the method's signature, the callsite and
definition have to agree. These don't work:</p>
<div class="codehilite"><pre><span class="s">&quot;string&quot;</span><span class="p">.</span><span class="n">count</span><span class="p">()</span>
<span class="n">list</span><span class="p">.</span><span class="n">clear</span>
</pre></div>
<h3>Operators <a href="#operators" name="operators" class="header-anchor">#</a></h3>
<p>Operators are just special syntax for a method call on the left hand operand
(or only operand in the case of unary operators like <code>!</code> and <code>~</code>). In other
words, you can think of <code>a + b</code> as meaning <code>a.+(b)</code>.</p>
<p>You can define operators in your class like so:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="c1">// Infix:</span>
<span class="o">+</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;Adding to a unicorn?&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// Prefix:</span>
<span class="o">!</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;Negating a unicorn?!&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>This can be used to define any of these operators:</p>
<div class="codehilite"><pre><span class="c1">// Infix:</span>
<span class="o">+</span> <span class="o">-</span> <span class="o">*</span> <span class="o">/</span> <span class="o">%</span> <span class="o">&lt;</span> <span class="o">&gt;</span> <span class="o">&lt;=</span> <span class="o">&gt;=</span> <span class="o">==</span> <span class="o">!=</span> <span class="o">&amp;</span> <span class="o">|</span>
<span class="c1">// Prefix:</span>
<span class="o">!</span> <span class="o">~</span> <span class="o">-</span>
</pre></div>
<p>Note that <code>-</code> can be both a prefix and infix operator. If there's a parameter
list, it's the infix one, otherwise, it's prefix. Since Wren supports
overloading by arity, it's no problem for a class to define both.</p>
<h3>Subscript operators <a href="#subscript-operators" name="subscript-operators" class="header-anchor">#</a></h3>
<p><strong>TODO</strong></p>
<h3>Setters <a href="#setters" name="setters" class="header-anchor">#</a></h3>
<p><strong>TODO</strong></p>
<h2>Constructors <a href="#constructors" name="constructors" class="header-anchor">#</a></h2>
<p>To create a new instance of a class, you use the <code>new</code> keyword. We can make a
unicorn like so:</p>
<div class="codehilite"><pre><span class="k">new</span> <span class="n">Unicorn</span>
</pre></div>
<p>You almost always want to define some state or do some other initialization on
a new object. For that, you'll want to define a constructor, like so:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="k">new</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;I am a constructor!&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>When you create an instance with <code>new</code>, its constructor will be invoked. It's
just a method with a special name. Like methods, you can pass arguments to the
constructor by adding a parenthesized parameter list after <code>new</code>:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">color</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;My name is &quot;</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s2">&quot; and I am &quot;</span> <span class="o">+</span> <span class="n">color</span> <span class="o">+</span> <span class="s2">&quot;.&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>Values are passed to the constructor like so:</p>
<div class="codehilite"><pre><span class="k">new</span> <span class="n">Unicorn</span><span class="p">(</span><span class="s2">&quot;Flicker&quot;</span><span class="p">,</span> <span class="s2">&quot;purple&quot;</span><span class="p">)</span>
</pre></div>
<p>Like other methods, you can overload constructors by <a href="#signature">arity</a>.</p>
<h2>Fields <a href="#fields" name="fields" class="header-anchor">#</a></h2>
<p>All state stored in instances is stored in <em>fields</em>. Each field has a named
that starts with an underscore.</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Rectangle</span> <span class="p">{</span>
<span class="n">area</span> <span class="p">{</span> <span class="n">_width</span> <span class="o">*</span> <span class="n">_height</span> <span class="p">}</span>
<span class="c1">// Other stuff...</span>
<span class="p">}</span>
</pre></div>
<p>Here, <code>_width</code> and <code>_height</code> in the <code>area</code> <a href="classes.html#methods">getter</a> refer
to fields on the rectangle instance. You can think of them like <code>this.width</code>
and <code>this.height</code> in other languages.</p>
<p>When a field name appears, Wren looks for the nearest enclosing class and looks
up the field on the instance of that class. Field names cannot be used outside
of an instance method. They <em>can</em> be used inside a <a href="functions.html">function</a>
in a method. Wren will look outside any nested functions until it finds an
enclosing method.</p>
<p>Unlike <a href="variables.html">variables</a>, fields are implicitly declared by simply
assigning to them. If you access a field before it has been initialized, its
value is <code>null</code>.</p>
<h3>Encapsulation <a href="#encapsulation" name="encapsulation" class="header-anchor">#</a></h3>
<p>All fields are <em>private</em> in Wren&mdash;an object's fields can only be directly
accessed from within methods defined on the object's class. You cannot even
access fields on another instance of your own class, unlike C++ and Java.</p>
<p>If you want to make a property of an object visible, you need to define a
getter to expose it:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Rectangle</span> <span class="p">{</span>
<span class="n">width</span> <span class="p">{</span> <span class="n">_width</span> <span class="p">}</span>
<span class="n">height</span> <span class="p">{</span> <span class="n">_height</span> <span class="p">}</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
<p>To allow outside code to modify the field, you'll also need to provide setters:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Rectangle</span> <span class="p">{</span>
<span class="n">width</span><span class="o">=</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span> <span class="n">_width</span> <span class="o">=</span> <span class="n">value</span> <span class="p">}</span>
<span class="n">height</span><span class="o">=</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span> <span class="n">_height</span> <span class="o">=</span> <span class="n">value</span> <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>One thing we've learned in the past forty years of software engineering is that
encapsulating state tends to make code easier to maintain, so Wren defaults to
keeping your object's state pretty tightly bundled up. Don't feel that you have
to or even should define getters or setters for most of your object's fields.</p>
<h2>Metaclasses and static members <a href="#metaclasses-and-static-members" name="metaclasses-and-static-members" class="header-anchor">#</a></h2>
<p><strong>TODO</strong></p>
<h3>Static fields <a href="#static-fields" name="static-fields" class="header-anchor">#</a></h3>
<p>A name that starts with <em>two</em> underscores is a <em>static</em> field. They work
similar to <a href="#fields">fields</a> except the data is stored on the class itself, and
not the instance. They can be used in <em>both</em> instance and static methods.</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Foo</span> <span class="p">{</span>
<span class="c1">// Set the static field.</span>
<span class="kd">static</span> <span class="kd">set</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="p">{</span>
<span class="n">__a</span> <span class="o">=</span> <span class="n">a</span>
<span class="p">}</span>
<span class="n">setFromInstance</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="p">{</span>
<span class="n">__a</span> <span class="o">=</span> <span class="n">a</span>
<span class="p">}</span>
<span class="c1">// Can use __a in both static methods...</span>
<span class="kd">static</span> <span class="n">bar</span> <span class="p">{</span> <span class="n">__a</span> <span class="p">}</span>
<span class="c1">// ...and instance ones.</span>
<span class="n">baz</span> <span class="p">{</span> <span class="n">__a</span> <span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>Just like instance fields, static fields are initially <code>null</code>:</p>
<div class="codehilite"><pre><span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">Foo</span><span class="p">.</span><span class="n">bar</span><span class="p">)</span> <span class="c1">// null.</span>
</pre></div>
<p>They can be used from static methods:</p>
<div class="codehilite"><pre><span class="n">Foo</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="s2">&quot;foo&quot;</span><span class="p">)</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">Foo</span><span class="p">.</span><span class="n">bar</span><span class="p">)</span> <span class="c1">// foo.</span>
</pre></div>
<p>And also instance methods. When you do so, there is still only one static field
shared among all instances of the class:</p>
<div class="codehilite"><pre><span class="kd">var</span> <span class="n">foo1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Foo</span>
<span class="kd">var</span> <span class="n">foo2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Foo</span>
<span class="n">foo1</span><span class="p">.</span><span class="n">setFromInstance</span><span class="p">(</span><span class="s2">&quot;updated&quot;</span><span class="p">)</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">foo2</span><span class="p">.</span><span class="n">baz</span><span class="p">)</span> <span class="c1">// updated.</span>
</pre></div>
<h2>Inheritance <a href="#inheritance" name="inheritance" class="header-anchor">#</a></h2>
<p>A class can inherit from a "parent" or <em>superclass</em>. When you invoke a method
on an object of some class, if it can't be found, it walks up the chain of
superclasses looking for it there.</p>
<p>By default, any new class inherits from <code>Object</code>, which is the superclass from
which all other classes ultimately descend. You can specify a different parent
class using <code>is</code> when you declare the class:</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Pegasus</span> <span class="k">is</span> <span class="n">Unicorn</span> <span class="p">{}</span>
</pre></div>
<p>This declares a new class <code>Pegasus</code> that inherits from <code>Unicorn</code>.</p>
<p>Note that you should not create classes that inherit from the built-in types (Bool, Num, String, Range, List). The built-in types expect their internal bit representation to be very specific and get horribly confused when you invoke one of the inherited built-in methods on the derived type.</p>
<p>The metaclass hierarchy does <em>not</em> parallel the regular class hierarchy. So, if
<code>Pegasus</code> inherits from <code>Unicorn</code>, <code>Pegasus</code>'s metaclass will not inherit from
<code>Unicorn</code>'s metaclass. In more prosaic terms, this means that static methods
are not inherited.</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="c1">// Unicorns cannot fly. :(</span>
<span class="kd">static</span> <span class="n">canFly</span> <span class="p">{</span> <span class="kc">false</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Pegasus</span> <span class="k">is</span> <span class="n">Unicorn</span> <span class="p">{}</span>
<span class="n">Pegasus</span><span class="p">.</span><span class="n">canFly</span> <span class="c1">// ERROR: Static methods are not inherited.</span>
</pre></div>
<p>Constructors, however, initialize the instance <em>after</em> it has been created.
They are defined as instance methods on the class and not on the metaclass.
That means that constructors <em>are</em> inherited.</p>
<div class="codehilite"><pre><span class="kd">class</span> <span class="nc">Unicorn</span> <span class="p">{</span>
<span class="k">new</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="p">{</span>
<span class="n">IO</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s2">&quot;My name is &quot;</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s2">&quot;.&quot;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">class</span> <span class="nc">Pegasus</span> <span class="k">is</span> <span class="n">Unicorn</span> <span class="p">{}</span>
<span class="k">new</span> <span class="n">Pegasus</span><span class="p">(</span><span class="s2">&quot;Fred&quot;</span><span class="p">)</span> <span class="c1">// Prints &quot;My name is Fred.&quot;.</span>
</pre></div>
</main>
</div>
<footer>
<div class="page">
<div class="main-column">
<p>Wren lives <a href="https://github.com/munificent/wren">on GitHub</a> &mdash; Made with &#x2764; by <a href="http://journal.stuffwithstuff.com/">Bob Nystrom</a> and <a href="https://github.com/munificent/wren/blob/master/AUTHORS">friends</a>.</p>
<div class="main-column">
</div>
</footer>
</body>
</html>