Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 7: The Specialist Problem

Dr. Reyes could do everything Dr. Portbridge could, checkups, vaccinations, prescriptions. Plus surgery. Modeling him as a plain Veterinarian would lose the surgery part. Creating a completely separate Surgeon concept would duplicate all the shared fields. Neither option felt right.


The problem

You have two kinds of things that share most of their structure but differ in some aspects. Duplicating attributes across concepts is fragile: change one, forget the other. You need inheritance.

#sub: concept inheritance


concept Veterinarian:
  has name: one string
  has license_number: one string
  has specialization: optional string

concept Surgeon:
  sub Veterinarian
  has surgery_count: one int
  has certified_procedures: at least 1 string

The keyword sub says: “A Surgeon is a specialization of Veterinarian.” A Surgeon automatically has name, license_number, and specialization (inherited from Veterinarian), plus its own surgery_count and certified_procedures.

In OWL terms, this is rdfs:subClassOf. In object-oriented terms, it’s inheritance. In plain English: every Surgeon is a Veterinarian, but not every Veterinarian is a Surgeon.

Building a hierarchy

Let’s extend this further. The clinic is growing and has different roles:


concept Veterinarian:
  has name: one string
  has license_number: one string
  has specialization: optional string

concept Surgeon:
  sub Veterinarian
  has surgery_count: one int
  has certified_procedures: at least 1 string

concept Dentist:
  sub Veterinarian
  has dental_certification: one string

concept Intern:
  sub Veterinarian
  has university: one string
  has year: one int

All four concepts share name, license_number, and specialization. Each adds its own details.

Inheritance for animals too

The Species enum tells us what kind of animal something is, but it doesn’t let us attach species-specific attributes. With inheritance, we can:


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 Bird:
  sub Animal
  has wingspan: optional float
  has can_fly: one boolean

A Dog is an Animal with breed and neuter status. A Bird is an Animal with a wingspan and flight ability. The shared core (name, species, age, etc.) is defined once and inherited everywhere.

Ordering convention

Inside a concept body, put sub first, then has declarations. This isn’t enforced by the parser, but it’s the standard Dolfin style:


concept Surgeon:
  sub Veterinarian            # ← parent first
  has surgery_count: one int  # ← then own attributes

The story so far


package <http://happypaws.com/clinic>:
  dolfin_version "1"
  version "0.1.0"
  author "Dr. Helen Portbridge"
  description "The Happy Paws veterinary clinic data model"

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 first_name: one string
  has last_name: one string
  has phone_numbers: at least 1 string
  has email: optional string
  has address: optional string

concept Veterinarian:
  has name: one string
  has license_number: one string
  has specialization: optional string

concept Surgeon:
  sub Veterinarian
  has surgery_count: one int
  has certified_procedures: at least 1 string

concept Dentist:
  sub Veterinarian
  has dental_certification: one string

concept Intern:
  sub Veterinarian
  has university: one string
  has year: one int

concept Vaccination:
  has vaccine_name: one string
  has date_administered: one string
  has batch_number: 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 Bird:
  sub Animal
  has wingspan: optional float
  has can_fly: 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

Try it

The clinic just hired a Radiologist (a specialized Veterinarian). They have a machine_certified_on attribute (a string, the machine name) and a readings_performed count. Add the concept:


concept Veterinarian:
  has name: one string
  has license_number: one string
  has specialization: optional string

concept Surgeon:
  sub Veterinarian
  has surgery_count: one int
  has certified_procedures: at least 1 string

# Add Radiologist here

The model now captured the difference between Dr. Portbridge (general practice), Dr. Reyes (surgeon), and the new dental specialist who started on Tuesdays. But Dr. Portbridge noticed something: she was manually checking whether each animal’s vaccinations were up to date, whether appointments with surgeons involved surgical cases, whether overdue checkups needed follow-up reminders. She was the reasoning engine, and she was exhausted.

“What if the system could figure these things out by itself?”