Skip to main content

The Subjekt Model

The Subjekt model describes the Subjekt's semantic model and the files used to create it. Subjekt models are used to describe data structures, smart contracts, services, and subjects.

Subjekt Overview​

The Subjekt model can be represented in various forms, including a semantic model, through the Interface Definition Language (IDL), and as an Abstract Syntax Tree (AST) in JSON format.

Subjekt Overview

Semantic model​

The in-memory model used by tools. The semantic model may be serialized into one or more model file representations.

Model File​

A file on the file system in a specific format. Model files can be divided across multiple files for better readability or modularity, and these files can use different formats (.subjekt or .json). It's the responsibility of the tooling to merge all necessary model files into a valid semantic model, as model files do not explicitly include one another.

Representation​

A particular model file format such as .subjekt or .json. Representations are loaded into the semantic model by mapping the representation to the shape types in the semantic model.

  • Subjekt IDL: a human-readable format that aims to streamline authoring, reading, and sharing models.
  • JSON AST: a machine-readable JSON-based format.

Semantic Model​

The semantic model is an in-memory model used by tools. It is independent of any particular serialized representation. The semantic model contains the metadata and a graph of shapes connected by shape IDs.

Semantic Model

  • Metadata: Metadata is a schema-less extensibility mechanism used to associate metadata to an entire model.
  • Prelude: The prelude defines various simple shapes and every trait defined in the core specification.
  • Shape: Shapes are named definitions that describe the data structures.
  • Shape ID: A Shape ID is used to identify shapes defined in the model.
  • Trait: Traits are applied to shapes to associate metadata to a shape.

Metadata​

Metadata is a schema-less extensibility mechanism used to associate metadata to an entire model. Metadata is defined using a node value. The following example configures a model validator:

metadata validators = [
{
name: "EmitEachSelector"
id: "OperationInputName"
message: "This shape is referenced as input but the name does not end with 'Input'"
configuration: {
selector: "operation -[input]-> :not([id|name$=Input i])"
}
}
]

When a conflict occurs between top-level metadata key-value pairs, the following conflict resolution logic is used:

  1. If both values are arrays, the values of both arrays are concatenated into a single array.
  2. Otherwise, if both values are exactly equal, the conflict is ignored.
  3. Otherwise, the conflict is invalid.

Node Values​

Node values are JSON-like values used to define metadata and the value of an applied trait.

TypeDescription
arrayA list of heterogeneous node values
nullThe lack of value
numberA double precision floating point number
objectA map of string keys to heterogeneous node values
stringA UTF-8 string

The following example defines a trait using a node value:

@length(min: 1, max: 10)
string MyString

Shapes​

Shapes are named definitions of types. Shapes are visualized using the below diagram:

Shapes

Shapes are grouped intro three categories, Simple, Aggregate, and Subject shapes.

Simple Shapes​

Simple shape types are fundamental data types that do not contain nested types or shape references. They are used to define the properties of states and behaviors within subjects. Below is a comprehensive list of simple shapes available in Subjektify.

TypeDescription
addressEthereum wallet addresses generated using the Keccak-256 hashing algorithm.
blobUninterpreted binary data.
booleanA true or false value.
byteAn 8-bit unsigned integer.
bytesAn array of bytes.
documentArbitrary JSON-like data structure.
doubleA double-precision floating point number.
floatA single-precision floating point number.
intA signed integer.
int8An 8-bit signed integer.
int16A 16-bit signed integer.
int32A 32-bit signed integer.
int64A 64-bit signed integer.
int128A 128-bit signed integer.
int256A 256-bit signed integer.
noneA placeholder type indicating the absence of a value.
stringA sequence of characters.
timestampA point in time, typically represented as a UNIX timestamp.
uintAn unsigned integer.
uint8An 8-bit unsigned integer.
uint16A 16-bit unsigned integer.
uint32A 32-bit unsigned integer.
uint64A 64-bit unsigned integer.
uint128A 128-bit unsigned integer.
uint256A 256-bit unsigned integer.

These types form the building blocks for more complex structures and interactions within your Subjektify projects.

Aggregate Shapes​

Aggregate types contain configurable member references to others shapes.

TypeDescription
enumAn enumeration type, representing a fixed set of named values.
listOrdered collection of homogeneous values.
mapMap data structure that maps string keys to homogeneous values.
structureFixed set of named heterogeneous members.

Subject Shapes​

Subject types define various components within the Subject-Oriented Programming (SOP) framework, each serving distinct roles within the subject's lifecycle and interactions.

TypeDescription
subjectRepresents the overarching container of states, behaviors, and subscriptions.
behaviorDefines actionable functions or methods within a subject.
eventEvents define specific conditions or triggers that activate behaviors.
errorErrors define types structures for custom errors.

Shape ID​

A shape ID is used to refer to shapes in the model. All shapes have an assigned shape ID. Shape IDs have the following syntax:

subjekt.example.foo#ExampleShapeName$memberName
└─────────┬──────┘ └───────┬──────┘ └────┬───┘
(Namespace) (Shape name) (Member name)
└──────────────┬────────────┘
(Relative shape ID)
└──────────────────────┬───────────────────────┘
(Absolute shape ID)
  • Absolute shape ID: An absolute shape ID starts with a namespace, followed by "#", followed by a relative shape ID.
  • Relative shape ID: A relative shape ID contains a shape name and an optional member name. The shape name and member name are separated by the "$" symbol if a member name is present.
  • Namespace: A namespace is a mechanism for logically grouping shapes in a way that makes them reusable alongside other models without naming conflicts. A semantic model may contain shapes defined across different namespaces.
  • Shape name: The name of the shape within a namespace. Model authors should utilize a strict form of PascalCase in which only the first letter of acronyms, abbreviations, and initialisms are capitalized. For example, prefer UserId over UserID.

Traits​

Prelude​

All Subjekt models include a prelude. A prelude defines all types and traits defined in the core specification. Shapes in the prelude do not need to reference subjektify's default namespace when usin the Subjekt IDL. However, the JSON AST model requires the namespace to be defined for all shape IDs. The complete prelude can be found here.