Chapter 6. The Core Concepts
KerML's core layer essentially consists of the elements Type, Classifier, Feature and Specialization such that
- Classifiers and features are types.
- Types may have features (so, also features may have features).
- A type T may specialize another type S. Then T is a subtype of S and S is a supertype of T. A subtype inherits all features of its supertypes.
These principles are described by the following meta-model:
Both Classifiers (like data types, classes and associations) and Features (like attributes, connectors and steps) are Types. A feature has a domain, called featuring type, and a range, called (featured) type.
The current KerML spec defines FeatureTyping as a form of specialization, as shown in the diagram above. Since this would imply that features specialize their range, this design choice of KerML seems questionable. See also the note below in Section 6.3.
6.1. Types
Types classify things in a modeled system. The set of things classified by a type is the extent of the type, each member of which is an instance of the type. Everything being modeled is an instance of the type
Anything
from theBase
library.
KerML distinguishes between two kinds of types: classifiers and features.
Types are namespaces, enabling them to have members via membership relationships to other elements identified as their members.
Types can be declared to specialize, and to be disjoint from, other types:
type Mammal specializes Animal disjoint from Mineral; disjoint Person::parents from Person::children;
The symbol :> can be used interchangeably with the keyword specializes
.
Unioning, intersecting, and differencing are relationships between a type and a set of other types:
type Person unions Adult, Child; type A intersects B, C; type X differences Y, Z;
Differencing specifies that a type classifies everything that is classified by the first of the differenced types but not by any of the remaining types.
Declaring a type to be abstract means that all instances of the type must also be instances of at least one concrete subtype:
abstract type Animal; type Mammal specializes Animal;
6.2. Classifiers
Classifiers are types that classify things in the modeled system, as distinct from features, which model the relations between them
Classifiers are typically declared together with a set of features:
classifier Person { feature name : String; feature age : Integer; }
6.3. Features
Features are types that classify how things in a modeled system are related. A feature relates instances in the intersection of the extents of its featuring types (the domain) with instances in the intersection of the extents of its featured types (the co-domain). Instances in the domain of a feature are said to "have values" that are instances of the co-domain. [Note: an alternative, and preferable, term for 'co-domain' is range.]
Features are normally declared with a range (or co-domain) in the body of a type declaration, in which case the (featuring) type is their domain, as in the following example where the classifier Person is the domain of the features name, parents, siblings, children and cousins:
classifier Person { feature name[1] : String; feature parents[0..2] : Person; var feature siblings[*] : Person; var feature children[*] : Person inverse of parents; // a cousin is a child of a parent's sibling var feature cousins[*] : Person chains parents.siblings.children; }
Notice that the declarations of the features siblings, children and cousins are prefixed with the keyword var, which means that the values of these variable features for a particular occurrence may vary in time (each snapshot of the occurrence may have a different value). For the value of a non-variable feature, such as name and parents, there is no history (as represented by snapshot values), it simply holds for the occurrence.
We also call a structural feature a property, and the special case of a data-valued feature (having a data type as its range) an attribute, while we also call a behavioral feature an action feature or an action step.
While name is an attribute, the features parents, siblings, children and cousins are object-valued properties, all of them having Person as their range. For the features siblings, children and cousins, their multiplicity * ("zero-or-more") means that they are optional and multi-valued.
When the multiplicity of a feature is 1 ("exactly one"), the feature is mandatory and functional (or, in other words, single-valued), having exactly one value. When the value of a feature is a collection of values from its range, the feature is non-functional and its multiplicity is m..n where m is a natural number, n is a natural number or * (infinity), and 0 ≤ m ≤ n. Instead of 0..*, which means "neither mandatory nor functional", we can simply write the asterisk symbol *. Instead of [k..k] we can simply write [k].
When no explicit multiplicity is defined for a feature, its multiplicity is * by default, if no more restrictive multiplicity is inherited.
A feature that is declared within the body of a type is an owned feature of that type, so it automatically has that type as a featuring type.
The feature cousins
is declared by feature chaining to include, for a given person, all persons that are children of siblings of the parents of this person. The feature children
is declared by feature inverting to be the inverse of the feature parents
. That is, for each pair (p1, p2) in the extent of children
, the pair (p2, p1) is in the extent of parents
.
Features can also be declared at the package level independently of a type declaration:
feature name[1] : String; feature age[1] : Integer featured by Person;
Here, the feature name
is declared with the datatype String
as its range, and since no explicit domain is declared, the implicit domain is the pre-defined classifier Anything
(from the Base
library), while the feature age
is declared to have the explicit domain Person
, as expressed by the clause featured by Person
. A package-level feature is always referential and is semantically featured by the base type Anything
(which means that a value for it is available within any instance of any type). However, it is not syntactically an "owned" feature of Anything
, since it is, by definition, owned by a package. That means that it has no featuring types.
Type featuring, which can be declared with the keywords featured by
, is a relationship between a feature and a type, where the type is a featuring type of the feature. Feature membership is a kind of type featuring that also makes the feature an owned member of the featuring type.
Feature typing is a relationship between a feature and a type that identifies the type as a featured type of the feature, as expressed by the colon in between the feature name "age" and the datatype name "Integer" or, equivalently, by the clause typed by
in the following example:
feature age[1] typed by
Integer featured by Person;
According to the current semantics of KerML, feature typing is a certain form of specialization, which implies that a feature specializes its range. For instance, the feature
age
declared in the code example above would specialize its rangeInteger
and, consequently, any pairs from the extent ofage
, like (Tom, 37), would be instances of the datatypeInteger
, in addition to the "basic instances" representing integers, which is quite strange.
In certain cases, a feature may have more than one featuring type, as in the following example:
classifier Vehicle; classifier PoweredComponent; feature engine[1] : Engine featured by Vehicle, PoweredComponent;
In such a case, the domain of a feature is given by the intersection of its featuring types. That is, in the above example, an instance in the domain of engine must be both a Vehicle and a PoweredComponent.
Features may have certain type-level properties such as being unique, ordered, composite, derived, variable, constant, or having a direction, as shown in the following meta-model diagram:
A feature is unique and non-ordered by default. In the case of a multi-valued feature, this means that its value is an ordinary set, while the value of an ordered feature is an ordered set, and the value of an non-unique feature is a multiset. The following example declares a feature whose values form a sequence:
feature sensorReadings : Real [*] nonunique ordered;
The values of a composite feature represent components (separable parts) of the featuring instance. They cannot exist after the featuring instance ceases to exist, but this only applies to values at the time the instance goes out of existence and allows removing these values before that. Components also cannot be shared (they cannot be components of another instance of the feature's domain).
classifier Wheel { var composite feature rim[1] : Rim; var composite feature tire[1] : Tire; }
The values of a portion feature represent inseparable parts of the featuring instance. They cannot exist without the whole. For instance, the childhood of a person can be declared as a portion feature:
classifier Person { portion feature childhood : Occurrence; }
When a feature is derived, it typically has a bound feature value expression that completely determines its value at all times, such as in the following example:
classifier TestRecord { feature scores[1..*] : Integer; derived feature averageScore[1] : Rational = sum(scores)/size(scores); }
Features may be declared as either variable or constant (except for portion features). Values of a variable feature may vary for each snapshot of the featuring instance. Declaring a feature as variable implies that its historical values are of interest and considered to be part of a description of a featuring instance. A constant feature is constrained to have the same value over the entire lifetime of a featuring instance. When a feature is neither declared as variable nor constant, its historical values are not of interest and they are not considered to be part of a description of a featuring instance.
classifier Person { var feature name[1] : String; feature nickName[1] : String; constant feature birthDate[1] : Date; }
Notice that the concept of a directed feature (of a Behavior) replaces the UML concept of an operation parameter.
Except for isComposite, all other meta-properties apply to properties, only, and not to behavioral features.
Feature Overriding
The following example, adapted from a May 2025 post to the SysML v2 Release Google Group, illustrates the possibility of overriding (redefining) properties and action steps in SysML2:
part def Engine { action generateTorque; } part def Car { part eng[1] : Engine; perform eng.generateTorque; } part def DieselEngine :> Engine { dieselTorque :>> generateTorque { // produce diesel torque } } part def DieselCar :> Car { part :>> eng : DieselEngine; }
Notice how
- the part type DieselCar specializes Car by overriding its part property eng requiring it to be of type DieselEngine (instead of Engine),
- the part type DieselEngine specializes Engine by overriding its action feature generateTorque requiring it to produce diesel torque, which is a kind of torque.
The following explanation is based on an answer by Ed Seidewitz in that post.
A feature (like the property Car::eng) is formally defined as a mapping from its domain (Car) to its range (Engine). The redefining feature DieselCar::eng is a subset of that mapping such that any instance of DieselCar is mapped to an instance of DieselEngine, which is a kind of Engine. So, any Car instance has a corresponding value for eng that is an Engine, but for a DieselCar, that value will always be a DieselEngine.
Since the action feature generateTorque is not explicitly typed, it's implicitly typed by Action (predefined in the SysML2 library Actions), such that it represents a mapping from the domain Engine to the range Action. So, for each Engine instance, generateTorque will have values that are actions, but the library type definition Action doesn't specify any behavior. The redefining feature DieselEngine::dieselTorque is then a subset of the generateTorque mapping, so it also has values that are actions, but these are further extended with the additional features required to "produce diesel torque". Thus, any Engine instance has values for generateTorque that are actions, but, for a DieselEngine, these will always be as given for dieselTorque, including the behavior to "produce diesel torque".
Finally, consider the feature chain eng.generateTorque used in the perform action feature of Car, which will always have Action values. However, in DieselCar, the overriding (redefinition) of eng means that it will always have a value which is a DieselEngine. Which means that, for a DieselCar, eng.generateTorque will always be as given by dieselTorque. Which means that, for a DieselCar, the inherited perform action feature will always perform the action specified for dieselTorque, as desired.
Property Value Relationships
A property value relationship (called "feature value" in the spec) is a special kind of binding connector, binding a (possibly initial or default) value to a property.
An example of a bound (as opposed to initial) property value relationship, stating that a property's value is always obtained as the result of the value expression, and in this sense derived, is shown in the following example:
classifier TestRecord { feature scores[1..*] : Integer; derived feature averageScore[1] : Rational = sum(scores)/size(scores); }
An example of an initial property value relationship, stating that a property's initial value is obtained as the result of the value expression (but may be changed subsequently):
feature count[1] : Natural := 0;
An example of a bound property default value relationship:
feature cutoff[1] : Integer default 0.75 * averageScore;
An example of an initial property default value relationship:
feature engine[1] : Engine default := standardEngine;
These different forms of property value relationships combine the definition of a property (structural feature) with different forms of bindings.
Ordered Sets and Multi-Sets (Bags) as Values of Multi-Valued Features
A multi-valued feature declaration can include either or both of the keywords ordered
and nonunique
(in either order). For instance, we can declare that the value of a multi-valued feature spouses is a sequence of persons in the following way:
classifier Person { feature spouses[*] : Person nonunique ordered; }
If a feature is ordered, then for any domain instance, the values of the feature can be placed in order, indexed from 1 to the number of values. The default is that the feature is unordered.
If a feature is non-unique, then, for any domain instance, the same range instance may appear more than once as a value of the feature. The default is that the feature is unique.
Subsetting and Redefinition as Special Forms of Specialization
There are also several forms of specialization that apply specifically to features.
- Subsetting is a relationship between a specific feature (the subsetting feature) and a more general feature (the subsetted feature), where the specific feature may further constrain the featuring types, featured types and multiplicity of the general feature.
- Redefinition is a kind of subsetting in which the specific feature (the redefining feature) also replaces an otherwise inherited general feature (the redefined feature) in the context of the owning type of the specific feature.
The symbols :> and :>> can be used interchangeably with the keywords subsets
and redefines
, respectively.
An example of subsetting is the following:
classifier Wheel; classifier DriveWheel specializes Wheel; classifier Automobile { composite feature wheels[4] : Wheel; // Restricts multiplicity and type composite feature driveWheels[2] : DriveWheel subsets wheels; }
An example of redefinition is the following:
classifier WheeledVehicle { composite feature wheels[1..*] : Wheel; } classifier MotorizedVehicle specializes WheeledVehicle { composite feature redefines wheels[2..4]; }
In this example, the effective name of the redefining feature is "wheels", which is the same name as the redefined feature.
6.4. Open Questions
1 Why should a feature specialize its range?
TBD
A usage inherits the features from its definition in the same way that a specialized definition inherits from a more general definition element. For example, if a part usage vehicle is defined by a part definition Vehicle, and Vehicle has a mass defined by MassValue, then vehicle inherits the feature mass. In some cases, a usage may have more than one definition element, in which case the usage inherits the features from each of its definition elements, with the same rules for conflicting names as described above for subclassification. [SysML 7.6.1]
2 How to instantiate a classifier representing a continuous material type?
How can a continuous material type (with a mass noun as its name) be instantiated? Consider, for instance, the classifier Fuel defined in an example in 7.3.4.2:
classifier Fuel { portion feature fuelPortion : Fuel; }
The intended meaning is that any fuel quantity is an instance of Fuel. But how can Fuel be instantiated with the help of a constructor expression?
feature myFuel = new Fuel( ??? );
In the "SysML v2 Intro Textual Notation" slides, there is a comment that "Items may also model continuous materials that are stored in and/or flow between parts of a system." However, the term "item" is commonly understood as referring to discrete/countable things.
3 What are good examples of portion features?
Portion features are composite features where the values cannot exist without the whole, because they are the “same thing” as the whole. (For example, the portion of a person's life when they are a child cannot be added or removed from that person's life.)
Are the following good examples of portion features?
// from 7.3.4.2 of KerML classifier Fuel { portion feature fuelPortion : Fuel; }
classifier Person { portion feature childhood : Child; }