Files
wren/doc/site/classes.markdown

153 lines
4.8 KiB
Markdown
Raw Normal View History

2013-11-21 21:38:36 -08:00
^title Classes
2014-04-14 21:23:46 -07:00
^category types
2013-11-21 21:38:36 -08:00
2013-11-23 14:52:50 -08:00
Every value in Wren is an object, and every object is an instance of a class.
2014-02-17 13:56:41 -06:00
Even `true` and `false` are full-featured objects—instances of the `Bool` class.
2013-11-23 14:52:50 -08:00
2013-12-28 09:37:41 -08:00
Classes contain both *behavior* and *state*. Behavior is defined in *methods* which are stored in the class. State is defined in *fields*, whose values are stored in each instance.
2013-11-23 14:52:50 -08:00
## Defining a class
Classes are created using the `class` keyword, unsurprisingly:
2014-01-20 21:44:51 -08:00
:::dart
2013-11-23 14:52:50 -08:00
class Unicorn {}
This creates a class named `Unicorn` with no methods or fields.
2014-02-04 08:45:08 -08:00
## Methods
2013-12-28 09:37:41 -08:00
2014-02-04 08:45:08 -08:00
Once we've made a unicorn, to let it do stuff, we need to give it methods.
2013-12-28 09:37:41 -08:00
2014-01-20 21:44:51 -08:00
:::dart
2013-12-28 09:37:41 -08:00
class Unicorn {
prance {
2014-01-20 21:44:51 -08:00
IO.print("The unicorn prances in a fancy manner!")
2013-12-28 09:37:41 -08:00
}
}
This defines a `prance` method that takes no arguments. To support parameters, add a parenthesized parameter list after the method's name:
2014-01-20 21:44:51 -08:00
:::dart
2014-01-30 06:51:52 -08:00
class Unicorn {
prance(where, when) {
IO.print("The unicorn prances in " + where + " at " + when)
}
2013-12-28 09:37:41 -08:00
}
2014-02-04 08:45:08 -08:00
Unlike most other dynamically-typed languages, in Wren you can have multiple methods in a class with the same name, as long as they take a different number of parameters. In technical terms, you can overload by *arity*. So this class is fine:
2013-12-28 09:37:41 -08:00
2014-01-20 21:44:51 -08:00
:::dart
2013-12-28 09:37:41 -08:00
class Unicorn {
prance {
2014-01-20 21:44:51 -08:00
IO.print("The unicorn prances in a fancy manner!")
2013-12-28 09:37:41 -08:00
}
prance(where) {
2014-01-20 21:44:51 -08:00
IO.print("The unicorn prances in " + where)
2013-12-28 09:37:41 -08:00
}
prance(where, when) {
2014-01-20 21:44:51 -08:00
IO.print("The unicorn prances in " + where + " at " + when)
2013-12-28 09:37:41 -08:00
}
}
2014-02-04 08:45:08 -08:00
When you [call](method-calls.html) the `prance` method, it selects the right one based on how many arguments you pass it.
2013-12-28 09:37:41 -08:00
## Constructors
2014-02-04 08:45:08 -08:00
To create a new instance of a class, you use the `new` keyword. We can make a unicorn like so:
:::dart
new Unicorn
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:
:::dart
2014-02-04 08:45:08 -08:00
class Unicorn {
new {
IO.print("I am a constructor!")
}
}
When you create an instance with `new`, 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 `new`:
2014-02-04 08:45:08 -08:00
:::dart
2014-02-04 08:45:08 -08:00
class Unicorn {
new(name, color) {
IO.print("My name is " + name + " and I am " + color + ".")
}
}
Values are passed to the constructor like so:
:::dart
2014-02-04 08:45:08 -08:00
new Unicorn("Flicker", "purple")
2013-12-28 09:37:41 -08:00
Like other methods, you can overload constructors by arity.
## Operators
Operators are just special syntax for regular [method calls](method-calls.html) on the left hand operand (or only operand in the case of unary operators like `!` and `~`). You can define them like so:
:::dart
class Unicorn {
// Infix:
+(other) {
IO.print("Adding to a unicorn?")
}
// Prefix:
! {
IO.print("Negating a unicorn?!")
}
}
This can be used to define any of these operators:
:::dart
// Infix:
+ - * / % < > <= >= == != & |
// Prefix:
! ~ -
Note that `-` 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.
Operator overloading is really useful for types like vectors and complex numbers where the reader knows what the operators will do, but can make code deeply confusing if overused. When in doubt, use a real name.
## Setters
[Assignment](variables.html) *cannot* be overloaded. It isn't an operator, and its semantics are built right into the language.
**TODO: ...**
2013-12-28 09:37:41 -08:00
## Fields
**TODO**
## Metaclasses and static members
**TODO**
2013-11-23 14:52:50 -08:00
## Inheritance
A class can inherit from a "parent" or *superclass*. 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.
By default, any new class inherits from `Object`, which is the superclass from which all other classes ultimately descend. You can specify a different parent class using `is` when you declare the class:
2014-01-20 21:44:51 -08:00
:::dart
2013-11-23 14:52:50 -08:00
class Pegasus is Unicorn {}
This declares a new class `Pegasus` that inherits from `Unicorn`.
2014-02-04 08:45:08 -08:00
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if `Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from `Unicorn`'s metaclass. In more prosaic terms, this means that static methods are not inherited.
2013-12-28 09:37:41 -08:00
2014-02-04 08:45:08 -08:00
Constructors, however, initialize the instance *after* it has been created. They are defined as instance methods on the class and not on the metaclass. That means that constructors *are* inherited.
2013-12-28 09:37:41 -08:00
## Superclass method calls
**TODO**
2014-04-14 21:23:46 -07:00
**TODO: this**