Tips for Migrating to Luma
If you’re coming from another language, here are the key differences to keep in mind when writing Luma.
Coming from Python
| Python | Luma |
|---|---|
x = 5 |
x: int = 5 |
def greet(name): |
fn greet(name: str) -> str { |
for x in range(5): |
(0..5).walk(x) -> { |
for i, v in enumerate(items): |
items.walk(i, v) -> { |
continue |
skip |
break |
stop |
print(f"Hello {name}") |
print("Hello ${name}") |
if x: (truthy) |
if x != 0 { (explicit) |
None |
nil |
Optional[int] |
?int |
dict |
{str: int} |
set |
{int} |
list |
[int] |
Key differences:
- Luma requires type annotations on declarations
- No implicit truthiness:
if count:must beif count > 0 { - Braces
{}instead of indentation for blocks - No
classkeyword: usestruct+impl+trait - String interpolation uses
${}instead off"{}"
Coming from JavaScript/TypeScript
| JS/TS | Luma |
|---|---|
let x = 5 |
x: int = 5 |
const x = 5 |
lock x: int = 5 |
function greet(name) { |
fn greet(name: str) -> str { |
for (let i = 0; i < 5; i++) |
(0..5).walk(i) -> { |
array.forEach(x => ...) |
list.walk(x) -> ... |
continue |
skip |
break |
stop |
array.filter(x => x > 0) |
list.filter(x -> x > 0) |
`Hello ${name}` |
"Hello ${name}" |
null / undefined |
nil |
interface |
trait |
Key differences:
- Luma uses
->for lambdas, not=> =>is used for expression-body functions:fn double(x: int) -> int => x * 2- No
thiskeyword: methods useself - No
var/let/constdistinction: justname: typeorlock name: type - No semicolons needed
Coming from Go
| Go | Luma |
|---|---|
x := 5 |
x: int = 5 |
func greet(name string) string { |
fn greet(name: str) -> str { |
for i := 0; i < 5; i++ { |
(0..5).walk(i) -> { |
for _, v := range items { |
items.walk(v) -> { |
continue |
skip |
break |
stop |
fmt.Println(x) |
print(x) |
map[string]int |
{str: int} |
[]int |
[int] |
*int (nil pointer) |
?int (optional) |
json.Marshal(v) |
json.encode(v) |
json.Unmarshal(data, &v) |
json.decode(data) |
Key differences:
- Luma types use shorter names:
strnotstring,floatnotfloat64 - No pointers: optionals (
?T) replace nil pointer patterns - No goroutines or channels (concurrency is planned)
- Iteration uses
.walk()instead offor range - No explicit error returns: Luma uses optionals and panics for now
- String interpolation built in:
"${name}"instead offmt.Sprintf
Coming from Rust
| Rust | Luma |
|---|---|
let x: i32 = 5; |
x: int = 5 |
fn greet(name: &str) -> String { |
fn greet(name: str) -> str { |
for i in 0..5 { |
(0..5).walk(i) -> { |
for i in 0..=5 { |
(0..=5).walk(i) -> { |
continue |
skip |
break |
stop |
Option<i32> |
?int |
None |
nil |
impl Trait for Type |
impl Trait for Type { |
println!("{}", x) |
print(x) |
Key differences:
- No ownership, borrowing, or lifetimes
- No
match(pattern matching is planned) - Ranges use the same
..and..=syntax but require.walk()for iteration - Much simpler type system: no generics yet, no lifetime annotations
- Luma is designed for clarity over performance guarantees
General tips
-
Always annotate types on variable declarations. Luma uses type inference in expressions but declarations need explicit types.
-
Use
?Tfor nullable values. Regular types cannot benil. If a value might be absent, declare it as optional. -
Iterate with
.walk(), not traditional for loops. This is Luma’s universal iteration pattern for lists, sets, maps, ranges, and files. Useskipinstead ofcontinueandstopinstead ofbreak. -
String interpolation uses
${}inside double-quoted strings. No special prefix needed. -
No semicolons. Statements are terminated by newlines.
-
Immutability uses the
lockkeyword:lock pi: float = 3.14159