We cannot currently create methods for types defined in Roto.
This poses some questions:
- Where and how do we write these methods?
- Rust: In
implblocks. - Java/Python/C++ in the
typedeclaration. - Go: as separate functions.
- Rust: In
- How do we access
self/this? And how do we distinguish a static method from an instance method?- Rust: explicit
selfkeyword - Python: explicit but only conventional
self - Go: receiver argument (note: I dislike Go’s syntax because it makes searching functions harder)
- Java/JS: implicit
thisthat can be elided.
- Rust: explicit
I’m inclined to go with a mix of Rust and Go (never thought I’d say these words), where there’s no impl block, but there is an explicit self.
record Foo { ... }
# Static method
fn Foo.new() -> Foo { ... }
# Instance method
fn Foo.get_bar(self) -> Bar { ... }
There’s another option, which is to adopt Universal Function Call Syntax, which doesn’t seem too bad for a scripting language.
It would look like this:
record Foo { ... }
# Static method could be done like this:
fn Foo.new() -> Foo { ... }
# or
mod Foo {
fn new() -> Foo { ... }
}
fn get_bar(foo: Foo) -> Bar { ... }
One downside is that static methods are not supported in UFCS, so we have to bolt that on somehow. Another, probably more problematic downside is that it requires function overloading.
There are also plenty of languages that don’t feature methods and instead have some pipe operator, like Gleam:
fn spawn_task(i) {
task.async(fn() {
let n = int.to_string(i)
io.println("Hello from " <> n)
})
}
pub fn main() {
// Run loads of threads, no problem
list.range(0, 200_000)
|> list.map(spawn_task)
|> list.each(task.await_forever)
}
It’s a bit verbose, but that’s not too bad. I’m more worried about familiarity.