mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 14:18:42 +01:00
198 lines
6.6 KiB
Markdown
198 lines
6.6 KiB
Markdown
^title Method Calls
|
|
^category guide
|
|
|
|
Wren is deeply object oriented, so most code consists of invoking methods on
|
|
objects, usually something like this:
|
|
|
|
:::wren
|
|
System.print("hello")
|
|
|
|
You have a *receiver* expression (here `System`) followed by a `.`, then a name
|
|
(`print`) and an argument list in parentheses (`("hello")`). Multiple arguments
|
|
are separated by commas:
|
|
|
|
:::wren
|
|
list.insert("item", 3)
|
|
|
|
The argument list can also be empty:
|
|
|
|
:::wren
|
|
list.clear()
|
|
|
|
Semantically, all method calls work like this:
|
|
|
|
1. Evaluate the receiver and arguments from left to right.
|
|
2. Look up the method on the receiver's [class][].
|
|
3. Invoke it, passing in the argument values.
|
|
|
|
[class]: classes.html
|
|
|
|
## Signature
|
|
|
|
Unlike most other dynamically-typed languages, in Wren a class can have multiple
|
|
methods with the same *name*, as long as they have different *signatures*. The
|
|
signature includes the method's name along with the number of arguments it
|
|
takes. In technical terms, this means you can *overload by arity*.
|
|
|
|
<!-- TODO: Link to Random. -->
|
|
|
|
For example, the Random class has two methods for getting a random integer. One
|
|
takes a minimum and maximum value and returns a value in that range. The other
|
|
only takes a maximum value and uses 0 as the minimum:
|
|
|
|
:::wren
|
|
var random = Random.new()
|
|
random.int(3, 10)
|
|
random.int(4)
|
|
|
|
In a language like Python or JavaScript, these would both call a single `int()`
|
|
method, which has some kind of "optional" parameter. The body of the method
|
|
figures out how many arguments were passed and uses control flow to handle the
|
|
two different behaviors. That means first parameter represents "max unless
|
|
another parameter was passed, in which case it's min". Kind of gross.
|
|
|
|
In Wren, these are calls to two entirely separate methods, `int(_,_)` and
|
|
`int(_)`. This makes it easier to define "overloads" like this since you don't
|
|
need optional parameters or any kind of control flow to handle the different
|
|
cases.
|
|
|
|
It's also faster to execute. Since we know how many arguments are passed at
|
|
compile time, we can compile this to directly call the right method and avoid
|
|
any "if I got two arguments do this..." logic.
|
|
|
|
## Getters
|
|
|
|
Some methods exist to expose some stored or computed property of an object.
|
|
These are *getters* and have no parentheses:
|
|
|
|
:::wren
|
|
"string".count //> 6
|
|
(1..10).min //> 1
|
|
1.23.sin //> 0.9424888019317
|
|
[1, 2, 3].isEmpty //> false
|
|
|
|
Sometimes you have a method doesn't need any parameters, but modifies the object
|
|
or has some other side effect. For those, it's better to use empty parentheses:
|
|
|
|
:::wren
|
|
list.clear()
|
|
|
|
Also, when a method supports multiple arities, it's typical to include the `()`
|
|
in the zero-argument case to be consistent with the other versions:
|
|
|
|
Fiber.yield()
|
|
Fiber.yield("value")
|
|
|
|
A getter is *not* the same as a method with an empty argument list. The `()` is
|
|
part of the signature, so `count` and `count()` have different signatures.
|
|
Unlike Ruby's optional parentheses, Wren wants to make sure you call a getter
|
|
like a getter and a `()` method like a `()` method. These don't work:
|
|
|
|
:::wren
|
|
"string".count()
|
|
list.clear
|
|
|
|
## Setters
|
|
|
|
A getter lets an object expose a public "property" that you can *read*.
|
|
Likewise, a *setter* let you write to a property:
|
|
|
|
:::wren
|
|
person.height = 74 // Grew up!
|
|
|
|
Despite the `=`, this is just another syntax for a method call. From the
|
|
language's perspective, the above line is just a call to the `height=(_)`
|
|
method, passing in `74`.
|
|
|
|
Since the `=(_)` is in the setter's signature, an object can have both a getter
|
|
and setter with the same name without any collision. This way, you can have
|
|
read/write properties.
|
|
|
|
## Operators
|
|
|
|
Wren has most of the same operators you know and love with the same precedence
|
|
and associativity. We have three prefix operators:
|
|
|
|
:::wren
|
|
! ~ -
|
|
|
|
They are just method calls on their operand without any other arguments. An
|
|
expression like `!possible` means "call the `!` method on `possible`".
|
|
|
|
We also have a slew of infix operators—they have operands on both sides.
|
|
They are:
|
|
|
|
:::wren
|
|
== != < > <= >= .. ... | & + - * / % is
|
|
|
|
Like prefix operators, they are all funny ways of writing method calls. The left
|
|
operand is the receiver, and the right operand gets passed to it. So `a + b` is
|
|
semantically interpreted as "invoke the `+(_)` method on `a`, passing it `b`".
|
|
|
|
Note that `-` is both a prefix and an infix operator. Since they have different
|
|
signatures (`-` and `-(_)`), there's no ambiguity between them.
|
|
|
|
Most of these are probably familiar already. The `..` and `...` operators are
|
|
"range" operators. The number type implements those to create [range][]
|
|
objects, but they are method calls like other operators.
|
|
|
|
[range]: values.html#ranges
|
|
|
|
The `is` keyword is a "type test" operator. The base [Object][] class implements
|
|
it to tell if an object is an instance of a given class. You'll rarely need to,
|
|
but you can override `is` in your own classes. That can be useful for things
|
|
like mocks or proxies where you want an object to masquerade as a certain class.
|
|
|
|
[object]: core/object.html
|
|
|
|
## Subscripts
|
|
|
|
Another familiar syntax from math class is *subscripting* using square brackets
|
|
(`[]`). It's handy for working with collection-like objects. For example:
|
|
|
|
:::wren
|
|
list[0] // Get the first item in a list.
|
|
map["key"] // Get the value associated with "key".
|
|
|
|
You know the refrain by now. In Wren, these are method calls. In the above
|
|
examples, the signature is `[_]`. Subscript operators may also take multiple
|
|
arguments, which is useful for things like multi-dimensional arrays:
|
|
|
|
:::wren
|
|
matrix[3, 5]
|
|
|
|
These examples are subscript "getters", and there are also
|
|
corresponding *subscript setters*:
|
|
|
|
:::wren
|
|
list[0] = "item"
|
|
map["key"] = "value"
|
|
|
|
These are equivalent to method calls whose signature is `[_]=(_)` and whose
|
|
arguments are both the subscript (or subscripts) and the value on the right-hand
|
|
side.
|
|
|
|
<!--
|
|
|
|
**TODO: Integrate this into the infix expressions when "is" becomes a normal
|
|
overridable method.**
|
|
|
|
## The `is` operator
|
|
|
|
Wren has one last expression form. You can use the `is` keyword like an infix
|
|
operator. It performs a type test. The left operand is an object and the right
|
|
operand is a class. It evaluates to `true` if the object is an instance of the
|
|
class (or one of its subclasses).
|
|
|
|
:::wren
|
|
System.print(123 is Num) //> true
|
|
System.print("s" is Num) //> false
|
|
System.print(null is String) //> false
|
|
System.print([] is List) //> true
|
|
System.print([] is Sequence) //> true
|
|
|
|
-->
|
|
|
|
<a class="right" href="control-flow.html">Control Flow →</a>
|
|
<a href="maps.html">← Maps</a>
|