Migrating from Python to Gossamer¶
Python programs map well to Gossamer once you commit to three shifts:
static types, no implicit None, and pattern matching instead of
isinstance / duck-typing.
Differences that matter¶
| Python | Gossamer |
|---|---|
Dynamic typing, runtime TypeError. |
Static typing checked by gos check; most type errors are caught before run. |
None is implicit and pervasive. |
Option<T> is explicit. None exists only for Option. |
try / except. |
Result<T, E> + ?. No exception-style control flow. |
Duck typing via __dunder__ methods. |
Traits (impl Iterator for T, impl Display for T). |
str is a sequence of code points; indexing is cheap. |
String is UTF-8; indexing returns the byte at that offset. Use std::utf8 helpers for code-point iteration. |
dict, list, set are built-ins. |
std::collections::HashMap, Vec<T> (spelled [T] in types), HashSet<T>. |
| Decorators, metaclasses. | Attributes (#[test], #[cfg(...)], #[lint(allow(...))]). Not user-extensible. |
| Indentation is syntax. | Braces { } are syntax; gos fmt enforces a consistent shape. |
async def / await. |
go expr spawns a goroutine; blocking IO is fine. |
What stays the same¶
- List / dict / set comprehensions have direct iterator equivalents (
xs.filter(...).map(...).collect()). print("a", "b")→println("a", "b").- Named arguments → struct-literal call style:
Handler { log: true }.
Translation examples¶
Python:
def parse(line):
parts = line.strip().split(",")
return [int(p) for p in parts]
Gossamer:
fn parse(line: &str) -> Result<[i64], errors::Error> {
let mut out: [i64] = []
for piece in line.trim().split(',') {
let n: i64 = piece.trim().parse()
.map_err(|_| errors::new(format!("bad number: {piece}")))?
out.push(n)
}
Ok(out)
}
Python:
try:
value = risky()
except ValueError as e:
log(e)
value = default
Gossamer:
let value = match risky() {
Ok(v) => v,
Err(e) => { log(&e); default },
}