3.6 KiB
Chapter 1: Getting Started
Deimos can be run both interactively via a read-eval-print loop (REPL) or by compiling and running a given source file.
REPL
The REPL allows interactive programming similar to classic functional languages as well as Ruby. To start the REPL, run:
dm repl
Basics
All statements and expressions in the REPL are scoped under a synthetic function; in other words, variables persist through each input:
> let x = 2
> x
2
> let y = 3
> x + y
5
In addition to statements and expressions, functions can be defined in scope:
> fn double(x: Int) x * 2 end
> double(4)
8
Note that variables in the "top" scope are not available inside defined functions:
> let x = 7
> fn doubleX() x * 2 end
Error: Symbol x could not be found.
This requires the use of closures, which can "capture" variables in their containing scope:
> let x = 42
> let doubleX = { x * 2 }
> doubleX()
84
Note the difference in syntax between function declarations and closure declarations. As we will later see, closures are powerful constructs.
Introduction to Classes
Classes can also be defined in the REPL:
> class Dog \
pub name: String \
pub ctor(name: String) \
self.name = name \
end \
end
A few things are going on here. First, note the use the backslash to indicate that we are not done with our input (normally, a newline without a preceding backslash will cause the interpreter to consume everything input so far). Next, note our syntax for declaring a class, with hints of Rust and Ruby:
classkeyword: the usual meaningpubkeyword: makes a property or method available outside the class (i.e., non-private): Typeannotations: indicates the type of a property, parameter, or variable.ctorkeyword: marks a constructor. Note: Classes can only have one constructor.selfkeyword, followed by property name: like the usual construct in OOP languages.
Once we've defined our class, we can use it:
> let bear = Dog("Bear")
> let skye = Dog("Skye")
> bear.name
Bear
> skye.name
Skye
Note above how we construct instances of the class by "calling" the class, exactly like we do in Kotlin.
Class Declaration Short Form
The above class example is a bit verbose; Deimos offers the following equivalent, inspired by Kotlin:
class Dog(pub name: String) end
This is especially useful in the REPL, where we may just want to declare a data type for doing some data processing.
> class Point(pub x: Int, pub y: Int) end
> fn double(p: Point) Point(p.x * 2, p.y * 2) end
> let a = Point(3, 4)
> double(a)
Point(6, 8)
> let b = Point(5, 6)
> double(double(b))
Point(20, 24)
Compiling and Running Files
To compile and run a file, do:
dm run <your file name here>.dm
Note that the .dm extension is required in the command name (unlike java).
The above command will compile and immediately run the file. In order for a Deimos file to be executable, it must
contain a main function like the following:
fn main()
println("Hello, Deimos!")
end
Unlike the REPL, statements and expressions are not allowed in the top-level scope; they must be contained in a function or method:
let x = 10 // ERROR! Will not parse.
However, functions, classes, and other top-level constructs are allowed:
fn double(p: Point) -> Point
Point(p.x * 2, p.y * 2)
end
class Point(x: Int, y: Int) end
fn main()
let a = Point(1, 2)
let b = Point(3, 4)
println(double(a)) // Point(2, 4)
println(double(b)) // Point(6, 8)
end
let f = { a, b -> a + b } << 4
let x = f(5)
println(x) // 9