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

Type System

Every attribute (has) and property range in Dolfin has a type. A type is one of:

  • a primitive (string, int, float, boolean),
  • a temporal type (date, time, date_time, duration),
  • a quantity type (mass, length, speed, …),
  • a concept you declared, or
  • a closed concept (one of).

Types are what appears after the : in a has declaration or on either side of a property’s ->:


concept Person:
  has name: one string
  has born: optional date
  has employer: optional Organization

Primitive types

TypeDescriptionXSD datatypeValue examples
stringTextxsd:string"hello", ""
intIntegerxsd:integer0, 42, -7
floatFloating-pointxsd:float3.14, -0.5
booleanBooleanxsd:booleantrue, false

An int value is typed xsd:integer (unbounded), never xsd:int. See Turtle correspondence.


Temporal types

Temporal types carry dates, times, timestamps and durations. Their values are written as smart literals, a type keyword plus human-friendly notation in parentheses (see Temporal values). Dolfin parses the notation and emits the exact XSD lexical form.

TypeXSD datatypeSmart literalEmitted value
datexsd:datedate(June 1st 2026)2026-06-01
timexsd:timetime(2:30 PM UTC)14:30:00+00:00
date_timexsd:dateTimedate_time(June 1st 2026, 14:30)2026-06-01T14:30:00
durationxsd:durationduration(1y 6mo)P1Y6M

duration is also the time dimension of the quantity types below: duration(20 min) and quantity(20 min) are the same value, "PT20M"^^xsd:dayTimeDuration.

Two file-level directives supply defaults used while resolving temporal values:

  • @locale d/m/y: field order for numeric dates without an inline as mask.
  • @timezone <zone>: default timezone for time / date_time values without an inline offset.

See File-level directives. Inline information (an as mask, an inline offset) always overrides the directive.


Quantity types

A physical dimension is a built-in lowercase type, used like float or date. Its values are quantity(...) literals of that dimension, in any unit of it:


concept Dog:
  has weight: mass
  has topSpeed: optional speed
  has length: optional length   # a field may share a type's name

fact rex a Dog
  weight quantity(45 kg)
  topSpeed quantity(42 km/h)
  length quantity(1.2 m)
TypeRDF rangeValue exampleEmitted value
massquantitykind:Massquantity(45 kg)"45"^^<http://qudt.org/vocab/unit/KiloGM>
lengthquantitykind:Lengthquantity(1.2 m)"1.2"^^<http://qudt.org/vocab/unit/M>
speedquantitykind:Velocityquantity(42 km/h)"42"^^<http://qudt.org/vocab/unit/KiloM-PER-HR>
durationxsd:durationquantity(20 min)"PT20M"^^xsd:dayTimeDuration

The other quantity types are current, temperature, amount, luminosity, acceleration, force, pressure, energy, power, frequency, area, volume, density and momentum; the Units & Quantities reference lists each one with its dimension and QUDT quantity kind. A value of another dimension, or a bare number, is error S008. The names are not keywords: length or power remain valid field names. Older models that declare concept Mass and use Mass or unit.Mass as a range still compile, with lint warnings and quick-fixes towards mass (see legacy names).


Concept types

Any concept name is a type. Using it as a range means “an instance of that concept” (or a subtype of it, since sub inheritance is transitive):


concept Animal
concept Dog:
  sub Animal

concept Shelter:
  has residents: some Animal   # Dogs qualify, being Animals

Concept-typed values are references (:id) or inline anonymous blocks ([ ... ]) in facts, see Facts.

Class expressions: or, and, not

Concept types combine with or (either), and (both) and not (anything but):


concept Clinic:
  has patient: (Dog or Cat)
  has staff: (Person and not Intern)
  has partner: (Hospital or (Clinic and not Franchise))

property treats: (Vet or Nurse) -> not Human
  • Every or / and group is written in parentheses: (A or B), (A and B and C). A single name needs none.
  • Groups nest: (X or (Y and not T)).
  • and and or cannot be mixed in one group: (A or B and C) is an error, write (A or (B and C)) or ((A or B) and C).
  • not applies to what directly follows it: not T, or a whole group with not (A or B). It needs no parentheses, also at the top level (has partner: not Competitor).
  • or accepts primitives ((string or int)); and and not work on concepts only.
  • or, and and not are reserved words: a concept or field named and is written `and`.

See Turtle correspondence for the OWL form.

Video 2.4.2 · Union types, opening (0:04–0:38). Watch on PeerTube

Restrictions: with

with p: C is a type made of the things whose property p points to a C: an anonymous owl:Restriction. It declares nothing: p must already be a property (a property declaration or a has field), and a name that is unknown or is a concept is an error.

has and with are different verbs:

VerbMeaningDefault count
has p: C (concept body)declares the field p, with a global range0..* (any)
with p: C (type expression)a local constraint on an anonymous classat least one

A bare with p: C means “at least one p that is a C”: a restriction that required nothing would be useless. The forms are:

DolfinMeaning
with p: Cat least one value of p is a C
with p: only Cevery value of p is a C
with p: 2 Cexactly 2 values of p are Cs
with p: at least 2 C, with p: at most 3 C, with p: 1..4 Ca bounded number of C values
with p: = alice, with p: = "Bob"p has this exact value
with ^p: Cthe inverse of p: something that is a C points to this one through p

The counts are the cardinality keywords of has. only stays an ordinary identifier everywhere else.

Inline form. T with p: C is (T and (with p: C)), usable wherever a type is. Several withs chain, each one a member of the same and:


concept Person:
  has hasChild: Person
property knows: Person -> Person

property admires: (Person with hasChild: Person) -> Person
property trusts: Person with hasChild: Person with knows: only Person -> Person

A filler is a single name or a parenthesised group, so a chained with never attaches to the previous filler. Narrow a filler inline with parentheses: with hasChild: (Person with knows: Person).

Block form. Under sub T, equivalent to T, or a property’s domain T / range T line, an indented block of with lines is the intersection of T with every line. A block under a with line narrows that line’s filler:


concept Process
concept TemporalRegion
concept TemporalInterval
property occupiesTemporalRegion: Process -> TemporalRegion
property occurrentPartOf: Process -> Process

concept Act:
  sub Process
    with occupiesTemporalRegion: TemporalRegion   # Process and ∃occ.(TemporalRegion and …)
      with occurrentPartOf: TemporalInterval
    with ^occurrentPartOf: Process
  • with applies to concepts only: int with p: C and with age: int are errors.
  • with is a reserved word: a concept or field named with is written `with`.

See Turtle correspondence for the OWL form.

Defined concepts: equivalent to

sub X says every member of the concept is an X (necessary condition). equivalent to X says the concept is X: the members are exactly the things that are Xs (necessary and sufficient, owl:equivalentClass). X is any type expression, and takes the same with block as sub:


concept Person:
  has hasChild: Person

# Parent ≡ Person ⊓ ∃hasChild.Person
concept Parent:
  equivalent to Person
    with hasChild: Person

# Mother ⊑ Person ⊓ ∃hasChild.Person (necessary only)
concept Mother:
  sub Person
    with hasChild: Person
  • A concept may have several equivalent to lines, next to sub and has lines. Each line, and each type in equivalent to A, B, gives its own owl:equivalentClass statement, so the concept is equivalent to all of them. A with block needs a single type on its line.
  • There is no = form: equivalent to is the only way to say it.
  • Names in the line are checked like sub parents: an undeclared name is an error.

See Turtle correspondence.

Property domain and range lines

A class expression too long for property p: D -> R goes in a domain or range body line, with the same block form:


concept Process
concept TemporalRegion
concept TemporalInterval
property occupiesTemporalRegion
property occurrentPartOf

property partOfProcess
  sub occurrentPartOf
  domain Process
    with occupiesTemporalRegion: TemporalRegion
      with occurrentPartOf: TemporalInterval
  range Process
    with ^occupiesTemporalRegion: TemporalRegion

Each side is given once, either in the one-line form or in one line (error S014 otherwise). See Properties and Turtle correspondence.


Closed concepts (one of)

A closed concept enumerates a fixed set of named members; only those members are valid values:


concept Status:
  one of:
    Pending
    Active
    Archived

concept Ticket:
  has status: one Status

Members are referenced unquoted (Active), not as strings.


Cardinality

Cardinality is orthogonal to type: it constrains how many values of the type an attribute may hold (one, optional, some, N, N..M, …). It is written before the type. See Cardinality for the full table.


has tags: some string          # one or more strings
has born: at most 1 date       # zero or one date
has visits: date_time          # any number of timestamps