Chapter 8: Populating the Clinic
The model had grown up. Dr. Portbridge now had concepts for animals, owners, vets, and appointments, with cardinality constraints, enums, and a full inheritance hierarchy. But the system was still abstract: no actual dogs, no actual owners, no actual appointments. Biscuit, the nervous golden retriever, the first patient of the morning, was sitting in the waiting room. It was time to enter some real data.
The problem
So far, your Dolfin file contains descriptions of categories: what an Animal looks like, what an Appointment requires. It contains no individuals: no specific dog named Biscuit, no actual appointment on a Tuesday afternoon. This is the gap between a schema and a database.
Dolfin fills this gap with facts.
Your first fact
fact DrPortbridge a Veterinarian
name "Helen Portbridge"
licenseNumber "VET-2025-001"
The structure mirrors the schema:
factintroduces an instance declaration.DrPortbridgeis the instance’s identifier, you can reference it elsewhere asDrPortbridge.a Veterinarianasserts that this instance is of typeVeterinarian.- The indented block lists property assertions, one per line: the property name, then the value.
This is the same indentation-based style you already know from concept, rule, and package declarations. No new punctuation to learn.
Primitive values
Facts support all the same primitive types you use in has declarations:
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
allergies "pollen"
| Value kind | Example |
|---|---|
| String | "Biscuit" |
| Integer | 5 |
| Float | 32.4 |
| Boolean | true |
| Enum value | Dog (no quotes) |
Enum values are written without quotes; the parser resolves them against the property’s declared type.
Referencing other facts
When a property’s type is a concept (not a primitive), the value is a reference to another fact, written with its identifier:
fact JohnSmith a Owner
firstName "John"
lastName "Smith"
phoneNumbers "555-1234"
preferredVet DrPortbridge
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
owner JohnSmith
DrPortbridge and JohnSmith refer to the facts declared elsewhere in the file. Order doesn’t matter. The parser resolves identifiers after reading the whole file, so forward references work.
A bare identifier looks for the fact in the current file first, then in the one other file of the package that declares it. To point at a fact in a specific file, use its dotted path (people.customers.alice).
Don’t write
:JohnSmith. As in Turtle, a leading colon is the package’s default prefix::JohnSmithis the IRI<http://happypaws.com/clinic#JohnSmith>, not theJohnSmithfact ofclinic.dlf(which isclinic:JohnSmith).package.dlfdeclares no facts, so the analyzer warns that:JohnSmithpoints at the package namespace, whereJohnSmithis not declared.
Anonymous blocks
Some properties hold a value that is a structured object rather than a primitive or a reference. Biscuit’s vaccination record is a good example: it’s a Vaccination instance that only belongs to Biscuit, with no need for its own global identifier.
Use an anonymous block (square brackets) for this:
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
owner JohnSmith
vaccinations [
vaccineName "Rabies"
dateAdministered "2024-03-15"
batchNumber "RB-2024-0042"
]
The block’s type (Vaccination) is inferred from the property’s declared range. If the range is an abstract parent concept and you need to specify a subtype, you can add a SubType as the first line of the block:
animal [
a Dog
name "Rex"
]
Multi-valued properties
For properties with cardinality some, any, or at least N, simply repeat the property name on multiple lines:
fact JohnSmith a Owner
firstName "John"
lastName "Smith"
phoneNumbers "555-1234"
phoneNumbers "555-5678"
preferredVet DrPortbridge
Or write them as a comma-separated list:
fact JohnSmith a Owner
firstName "John"
lastName "Smith"
phoneNumbers "555-1234", "555-5678"
preferredVet DrPortbridge
Both forms are equivalent. The first reads like structured records; the second saves space when the values are short.
Multiple anonymous blocks work the same way. Biscuit received three vaccines:
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
owner JohnSmith
vaccinations [
vaccineName "Rabies"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Distemper"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Bordetella"
dateAdministered "2024-03-15"
]
Multiple types
A fact can assert membership in more than one concept, separated by commas:
fact Pixel a Cat, UnvaccinatedAnimal
name "Pixel"
species Cat
indoor true
This is useful when an instance simultaneously belongs to a base concept and a flag concept. Here, Pixel is both a Cat and (currently) an UnvaccinatedAnimal. In practice, flag concepts like UnvaccinatedAnimal are usually derived by rules rather than asserted directly, but the syntax supports both.
A day at the clinic
Here are the facts for opening day at Happy Paws:
# --- Staff ---
fact DrPortbridge a Veterinarian
name "Helen Portbridge"
licenseNumber "VET-2025-001"
fact DrReyes a Surgeon
name "Carlos Reyes"
licenseNumber "VET-2025-042"
surgeryCount 0
certifiedProcedures "Soft tissue"
certifiedProcedures "Orthopaedic"
# --- Owners ---
fact JohnSmith a Owner
firstName "John"
lastName "Smith"
phoneNumbers "555-1234"
preferredVet DrPortbridge
# --- Animals ---
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
owner JohnSmith
vaccinations [
vaccineName "Rabies"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Distemper"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Bordetella"
dateAdministered "2024-03-15"
]
fact Pixel a Cat
name "Pixel"
species Cat
indoor true
# --- Appointments ---
fact Appt001 a Appointment
animal Biscuit
`date` "2025-01-15"
reason "annual checkup"
urgency Routine
status Completed
diagnosis "Healthy"
treatments "Bordetella booster"
Notice:
Biscuitin the appointment refers back to theBiscuitfact.Pixelhas noowner, she’s the stray kitten. Theoptional Ownercardinality allows this.urgency Routineandstatus Completedare enum values without quotes.
The story so far
# package.dlf
package <http://happypaws.com/clinic>:
dolfin_version "1"
version "1.0.0"
author "Dr. Helen Portbridge"
description "The Happy Paws veterinary clinic data model"
# ============================================================
# clinic.dlf: Schema + Opening Day Facts
# ============================================================
# --- Schema (chapters 1–7) ---
concept Species:
one of:
Dog
Cat
Bird
Rabbit
Reptile
Other
concept Urgency:
one of:
Routine
Urgent
Emergency
concept AppointmentStatus:
one of:
Scheduled
InProgress
Completed
Cancelled
concept Owner:
has firstName: one string
has lastName: one string
has phoneNumbers: at least 1 string
has email: optional string
has address: optional string
has preferredVet: optional Veterinarian
concept Veterinarian:
has name: one string
has licenseNumber: one string
has specialization: optional string
concept Surgeon:
sub Veterinarian
has surgeryCount: one int
has certifiedProcedures: at least 1 string
concept Vaccination:
has vaccineName: one string
has dateAdministered: one string
has batchNumber: optional string
concept Animal:
has name: one string
has species: one Species
has age: optional int
has weight: optional float
has owner: optional Owner
has vaccinations: Vaccination
has allergies: string
concept Dog:
sub Animal
has breed: optional string
has neutered: one boolean
concept Cat:
sub Animal
has indoor: one boolean
concept Appointment:
has animal: one Animal
has `date`: one string
has reason: one string
has urgency: one Urgency
has status: one AppointmentStatus
has diagnosis: optional string
has treatments: string
has notes: optional string
property treatedBy: Animal -> Veterinarian
# --- Facts (chapter 8) ---
fact DrPortbridge a Veterinarian
name "Helen Portbridge"
licenseNumber "VET-2025-001"
fact DrReyes a Surgeon
name "Carlos Reyes"
licenseNumber "VET-2025-042"
surgeryCount 0
certifiedProcedures "Soft tissue"
certifiedProcedures "Orthopaedic"
fact JohnSmith a Owner
firstName "John"
lastName "Smith"
phoneNumbers "555-1234"
preferredVet DrPortbridge
fact Biscuit a Dog
name "Biscuit"
species Dog
age 5
weight 32.4
neutered true
owner JohnSmith
vaccinations [
vaccineName "Rabies"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Distemper"
dateAdministered "2024-03-15"
]
vaccinations [
vaccineName "Bordetella"
dateAdministered "2024-03-15"
]
fact Pixel a Cat
name "Pixel"
species Cat
indoor true
fact Appt001 a Appointment
animal Biscuit
`date` "2025-01-15"
reason "annual checkup"
urgency Routine
status Completed
diagnosis "Healthy"
treatments "Bordetella booster"
Try it
Register a new patient: a rabbit named Clover, owned by Maria Garcia (phone "555-9900"). Clover is 3 years old, weighs 1.8 kg, and has had one vaccination ("RHDV2", administered "2024-11-01").
fact MariaGarcia a Owner
firstName "Maria"
lastName "Garcia"
phoneNumbers "555-9900"
# Add Clover here
The system was no longer just a blueprint. It knew who worked at Happy Paws, who owned which animals, which vaccines had been given, and which appointments had been completed. Biscuit’s record showed three vaccinations and a clean checkup. Pixel’s record showed none at all.
Dr. Portbridge stared at Pixel’s entry. She was manually scanning for unvaccinated animals, overdue checkups, interns assigned to emergencies. Every check was a thing she had to remember to do. “What if the system could notice these things automatically?” she wondered. She needed the system to reason, to look at the facts and draw its own conclusions.