4
Chapter 4
Types and optionals
Silk types should make the shape of the data easy to inspect. Use named structs for records, scalar types at boundaries, and optionals when absence is expected.
Name the data shape
A struct gives related fields one concrete type.
src/profile.slk
package profile;
struct User {
id: u64;
name: string;
email: string?;
}
fn display_name (user: &User) -> string {
return user.name;
}
Return optional data deliberately
User? says a lookup can miss without turning that miss into a failure.
src/profile.slk
fn find_user (id: u64) -> User? {
if id == 1 {
return Some(User{
id: 1,
name: "Ada",
email: Some("ada@example.com"),
});
}
return None;
}
Handle the optional at the call site
Use a fallback when that is all the caller needs.
src/profile.slk
fn email_label (id: u64) -> string {
let user: User? = find_user(id);
match user {
Some(value) => {
return value.email ?? "no email";
},
None => {
return "missing user";
},
}
}
Check before building
The type checker should catch mismatched field, optional, and return shapes early.
Terminal
silk check src/profile.slk
Use optionals for normal absence. When callers need to know why something failed, move to a result shape
instead of overloading None.
What changed
Usermade the record shape inspectable.string?made a missing email explicit.User?modeled a lookup miss as normal data.matchhandled the optional before using the payload.
Chapter complete
Next, distinguish recoverable domain failures from typed contract errors.
Continue to results and errors