Lesson 08 of 16

Stencils — the signature feature

first-class data templates

download this lesson (.md) ↓ all lessons

8. Stencils — the signature feature

A stencil is what makes STencil unique: a first-class, reusable data template with computed fields. You define a shape once, then "stamp" it with ! to produce records. Think of a real stencil: a cut-out pattern you press onto material.

Defining a stencil

stencil User(name, age) {
    name: name,
    age: age,
    adult: age >= 18,           // computed field
    tag: name + "#" + age       // fields can use parameters
}

Fields are evaluated top to bottom, and a later field may use an earlier one.

Stamping with !

Name!(args) stamps the template and returns a record (object). Read fields with .:

let u = User!("Ember", 20);
print(u.name);    // Ember
print(u.adult);   // true
print(u.tag);     // Ember#20

Reshaping data

A stencil whose parameter is existing data transforms it into a new shape:

stencil Summary(u) {
    who: u.name,
    status: u.adult ? "adult" : "minor"
}
let s = Summary!(u);
print(s.who, s.status);   // Ember adult

Stamping over a collection: !*

Name!*list stamps every element and returns a new list — like a built-in map:

let people = [User!("Ada", 30), User!("Ben", 12), User!("Cem", 17)];
let summaries = Summary!*people;
for x in summaries {
    print(x.who, "=>", x.status);
}
// Ada => adult
// Ben => minor
// Cem => minor

Why stencils?

  • Declarative: describe the shape and derived values, not step-by-step construction.
  • Reusable: one template, stamp it anywhere.
  • Great for building/transforming data: API responses, records, config, game entities.
// game entities as stencils
stencil Monster(name, hp, power) {
    name: name, hp: hp, power: power,
    label: name + " (HP:" + hp + ")"
}
let dungeon = [Monster!("Goblin", 12, 3), Monster!("Dragon", 30, 9)];
for m in dungeon { print(m.label); }

Next: Error Handling