deimos-lang/dm-book/src/getting_started.md
2026-03-26 16:29:42 -05:00

160 lines
3.6 KiB
Markdown

# 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:
- `class` keyword: the usual meaning
- `pub` keyword: makes a property or method available outside the class (i.e., non-private)
- `: Type` annotations: indicates the type of a property, parameter, or variable.
- `ctor` keyword: marks a constructor. *Note: Classes can only have **one** constructor*.
- `self` keyword, 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
```