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

Appendix G: Relationship & Element Kinds Reference

Appendix A answers “how do I write this?”. This appendix answers a different question: “what is this, and does it actually exist?”

Every construct you write in SysML v2 produces one or more elements in an underlying metamodel – a fixed set of classes with fixed names and fixed inheritance. When you write part engine : Engine; you create a PartUsage whose typing is a FeatureTyping; when you write :> you create a Subclassification or a Subsetting depending on context. Tool APIs, model interchange files, diagnostic messages, and the specification itself all speak in these class names, so sooner or later you will meet one and need to know what it is.

The tables below are that dictionary. Read them in this direction:

  • Metamodel class is the authoritative name, as declared in the OMG vocabulary files. Where the class lives in KerML rather than SysML, that is noted – SysML inherits the whole KerML metamodel, so a great many “SysML” relationships are really KerML’s.
  • Specializes is the direct parent from rdfs:subClassOf. This is the fastest way to understand an unfamiliar kind: Redefinition specializes Subsetting specializes Specialization, which tells you almost everything about how redefinition behaves.
  • Textual form is what you type. Some kinds have a keyword, some have a punctuation token, some have both, and a few have no textual notation at all – they exist only as structure the parser creates for you. That last group is called out explicitly, because knowing you cannot write something directly saves you looking for a syntax that does not exist.
  • Clause is where the specification defines the notation. Clause numbers prefixed KerML are from the KerML specification; the rest are SysML.

Nothing here is extrapolated. Every row was checked against the vocabulary files, the specification text, and the reference grammar, and the handful of names that turn out not to exist are listed in their own section rather than quietly dropped.

A keyword does not imply a metaclass

Before the tables, one principle, because it is the single most common way to get lost in a reference like this: the notation and the metamodel are two separate vocabularies, and they do not line up one-to-one. A keyword you can type is not a promise that a class of the same name exists, and a class that exists is not a promise that there is a keyword for it. All three combinations occur:

Has a keywordNo keyword
Has a metaclassReturnParameterMembership, written returnResultExpressionMembership, written as a bare trailing expression
No metaclassmessage, which produces a FlowUsagenothing to name, so nothing to look up

So when a search of the vocabulary for some name comes up empty, that is not yet an answer. It rules out one of two possibilities, and the keyword may still be perfectly normative notation for a class with a different name. Each of the three cells above is worked through below – message under Messages, the two memberships in the membership table – and the same reasoning is what separates the genuinely non-existent names in Names that do not exist from the merely differently-named ones.

The specialization family

These are the relationships you write as a token inside a declaration. They all descend from Specialization, and each has both a symbol and an equivalent keyword. The pairs are fixed by the specification’s lexical structure, not by convention.

Metamodel classSpecializesTextual formClause
SpecializationRelationship:> or specializesKerML 7.3.2.3
SubclassificationSpecialization:> or specializes (on a definition)KerML 7.3.3.3
FeatureTypingSpecialization: or defined byKerML 7.3.4.3
SubsettingSpecialization:> or subsetsKerML 7.3.4.4
RedefinitionSubsetting:>> or redefinesKerML 7.3.4.5
ReferenceSubsettingSubsetting::> or references7.13.2
CrossSubsettingSubsetting=> or crosses7.13.2, 8.4.9.1

The six symbol/keyword pairs are defined as lexical terminals in clause 8.2.2.1.2, which is worth reading once because it is the only place they are all listed together:

DEFINED_BY  = ':'   | 'defined' 'by'
SPECIALIZES = ':>'  | 'specializes'
SUBSETS     = ':>'  | 'subsets'
REFERENCES  = '::>' | 'references'
CROSSES     = '=>'  | 'crosses'
REDEFINES   = ':>>' | 'redefines'

Two of these deserve a note. First, :> is genuinely ambiguous in the source – it creates a Subclassification on a definition and a Subsetting on a feature – so the metamodel class you get depends on what you attached it to, not on the token. Second, in SysML the long form of : is defined by, not typed by; typed by is the KerML spelling of the same terminal and typed is not a SysML keyword at all.

CrossSubsetting is the newest member of the family and is not covered elsewhere in this book. It lets a binary connection definition declare that each end must be one of the values of a feature reached through the other end, which keeps the two sides of the connection coordinated:

package CrossExample {
    part def Device {
        part connectingHub : Hub[1];
    }
    part def Hub {
        part connectedDevice : Device[*];
    }

    connection def DeviceToHub {
        end part device : Device crosses hub.connectedDevice;
        end part hub : Hub crosses device.connectingHub;
    }
}

Relationships with their own declaration syntax

These are written as standalone statements rather than as a token on some other declaration.

Metamodel classSpecializesTextual formClause
DependencyRelationshipdependency [<name> from] <clients> to <suppliers>;7.3.2
AnnotationRelationshipnone directly; created by doc, comment, and bare /* */ (// and //* notes are discarded at parse time and create no element)7.4.1
ImportRelationshipimport7.5.3
MembershipImportImportimport <ns>::<member>;7.5.3
NamespaceImportImportimport <ns>::*;7.5.3
ExposeImportexpose (inside a view)7.26.2
MembershipExposeExpose, MembershipImportexpose <ns>::<member>;7.26.2
NamespaceExposeExpose, NamespaceImportexpose <ns>::*;7.26.2
ConjugationRelationship~ (see note)KerML 7.3.2.4
PortConjugationConjugationcreated implicitly with every port def7.12.3
ConjugatedPortTypingFeatureTypingport <name> : ~<PortDef>;7.12.3
DisjoiningRelationshipdisjoint from (KerML only)KerML 7.3.2.5
UnioningRelationshipunions (KerML only)KerML 7.3.2.7
IntersectingRelationshipintersects (KerML only)KerML 7.3.2.7
DifferencingRelationshipdifferences (KerML only)KerML 7.3.2.7
FeatureChainingRelationship. in SysML; chains in KerML7.6.6, KerML 7.3.4.6
FeatureInvertingRelationshipinverse of (KerML only)KerML 7.3.4.7
TypeFeaturingRelationshipfeatured by (KerML only)KerML 7.3.4.8

Conjugation is a general KerML relationship that flips the direction of every feature of a type, and KerML writes it as ~ or conjugates on any type declaration. SysML exposes only the port-specific slice of it: every port def silently acquires a ConjugatedPortDefinition via a PortConjugation, and you reach it by writing ~ in front of the port definition’s name when typing a port. There is no general conjugates keyword in SysML, and conjugates is not in the SysML keyword list.

The last four rows – chains, inverse of, featured by, and the set operators – are the clearest example of a real kind with no SysML notation. All four classes are in the SysML vocabulary, because SysML inherits KerML’s metamodel wholesale, but none of the keywords appears in the SysML reserved-keyword list in clause 8.2.2.1.2, and the SysML specification text uses phrases like “featured by” only as prose describing semantics. In SysML you get FeatureChaining by writing a dotted path, and you do not get FeatureInverting or TypeFeaturing at all.

Tool note. sysml-rs uses one unified grammar for .sysml and .kerml files, so it will happily accept chains, featured by, and inverse of in a .sysml file and build real syntax nodes for them. Other tools are entitled to reject them. Do not rely on this.

Membership kinds

A membership is the relationship between a namespace and something inside it. Almost all of them are created structurally – you write a nested declaration and the parser decides which membership class it produced – but a surprising number do have a keyword, and those are the ones worth memorising.

Metamodel classSpecializesTextual formClause
MembershipRelationshipnone; created by nesting. Visibility via public / private / protectedKerML 7.2.5.2
OwningMembershipMembershipnone; created by nestingKerML 7.2.5.2
FeatureMembershipOwningMembershipnone; created by nesting a feature in a bodyKerML 7.3.2.6
EndFeatureMembershipFeatureMembershipend7.13.2
ParameterMembershipFeatureMembershipin / out / inout7.6.3
ReturnParameterMembershipParameterMembershipreturn7.19.2
ResultExpressionMembershipFeatureMembershipnone; the trailing bare expression of a body7.19.2
ElementFilterMembershipOwningMembershipfilter <booleanExpr>;7.5.4
SubjectMembershipParameterMembershipsubject7.22.2
ActorMembershipParameterMembershipactor7.21.2
StakeholderMembershipParameterMembershipstakeholder7.21.2
ObjectiveMembershipFeatureMembershipobjective7.22.2
RequirementConstraintMembershipFeatureMembershipassume or require7.21.2
FramedConcernMembershipRequirementConstraintMembershipframe7.21.2
RequirementVerificationMembershipRequirementConstraintMembershipverify7.24.2
StateSubactionMembershipFeatureMembershipentry / do / exit7.18.2
TransitionFeatureMembershipFeatureMembershipaccept (trigger) / if (guard) / do (effect)7.18.3
VariantMembershipOwningMembershipvariant; also each enum literal7.6.7
ViewRenderingMembershipFeatureMembershiprender7.26.2

ReturnParameterMembership and ResultExpressionMembership are the two most commonly doubted names on this list, and both are real KerML metaclasses, each with its own abstract-syntax subclause – KerML 8.3.4.7.8 and 8.3.4.7.7 respectively. They are the mirror image of message: where message is a keyword with no class behind it, these are classes, and only one of them has a keyword. The normative notation in KerML 8.2.5.7.1 shows the difference in two lines:

ReturnFeatureMember   : ReturnParameterMembership   = MemberPrefix 'return' ownedRelatedElement += FeatureElement
ResultExpressionMember : ResultExpressionMembership = MemberPrefix          ownedRelatedElement += OwnedExpression

One has 'return' between the prefix and the element; the other has nothing at all. A calc def body can carry both at once – a named, typed return parameter, and a trailing expression that supplies its value:

package ResultExample {
    calc def RectangleArea {
        in width : ScalarValues::Real;
        in height : ScalarValues::Real;
        return area : ScalarValues::Real;
        width * height
    }
}

The return area : ScalarValues::Real; line is the ReturnParameterMembership. The bare width * height on the last line is the ResultExpressionMembership: there is no keyword to write, and the only thing that marks it is its position as the final expression in the body. If you go looking for a result keyword, you will not find one.

Relationship-shaped usages

SysML’s connectors, flows and behavioural references are relationships and usages at the same time. That double life is visible in the Specializes column, where you will often see two parents.

Metamodel classSpecializesTextual formClause
ConnectorFeature, Relationshipconnect <a> to <b>7.13.2
BindingConnectorConnectorbind <a> = <b>;7.13.3
BindingConnectorAsUsageBindingConnector, ConnectorAsUsagebinding <name> bind <a> = <b>;7.13.3
SuccessionConnectorfirst <a> then <b>; / then <b>;7.13.5
SuccessionAsUsageConnectorAsUsage, Successionsuccession <name> first <a> then <b>;7.13.5
FlowConnector, Stepflow <src> to <tgt>;7.16.2
FlowUsageActionUsage, ConnectorAsUsage, Flowflow or message (see below)7.16.2
SuccessionFlowFlow, Successionsuccession flow <src> to <tgt>;7.16.2
SuccessionFlowUsageFlowUsage, SuccessionFlowsuccession flow7.16.2
AllocationUsageConnectionUsageallocate <a> to <b>;7.15.2
TransitionUsageActionUsagetransition [<name>] first <src> ... then <tgt>;7.18.3
AssignmentActionUsageActionUsageassign <target> := <expr>;7.17.9
PerformActionUsageActionUsage, EventOccurrenceUsageperform action <name> or perform <ref>7.17.6
ExhibitStateUsagePerformActionUsage, StateUsageexhibit state <name> or exhibit <ref>7.18.4
IncludeUseCaseUsagePerformActionUsage, UseCaseUsageinclude use case <name> or include <ref>7.25.3
EventOccurrenceUsageOccurrenceUsageevent occurrence <name> or event <ref>7.9.5
AssertConstraintUsageConstraintUsage, Invariantassert constraint { ... } or assert <ref>7.20.3
SatisfyRequirementUsageAssertConstraintUsage, RequirementUsagesatisfy requirement <ref> by <part>;7.21.4

Notice the pattern in the last several rows: each has a long form that declares something new, and a short form that just names an existing element. That short form is not a special case per construct – it is always the same mechanism. perform a;, exhibit s;, include u;, assume c;, require c;, verify r;, assert c;, event e;, and a bare entry a; all attach the named element by a ReferenceSubsetting, which is why ::> and references appear so far from the connection chapter that introduces them. The specification says so explicitly in clauses 7.9.5, 7.17.6, 7.18.2, 7.18.4, 7.20.3, 7.21.2 and 7.24.2.

Messages

message is the clean worked example of the principle above, and it is worth spelling out because two apparently contradictory statements about it are both true:

  1. message is real, normative SysML v2 syntax. It is in the reserved-keyword list in clause 8.2.2.1.2, it has a normative grammar production in clause 8.2.2.16, and the specification uses it in its own examples.
  2. There is no Message class in the metamodel. Searching SysML-vocab.ttl and Kerml-Vocab.ttl for one returns nothing, and that is the correct result, not a gap in the search.

The reconciliation is in the production’s return type. Clause 8.2.2.16 (Flows Textual Notation) declares:

Message : FlowUsage =
    OccurrenceUsagePrefix 'message'
    MessageDeclaration DefinitionBody
    { isAbstract = true }

Message : FlowUsage – the name on the left is the grammar rule, and the class it constructs is FlowUsage. So message is concrete syntax for an existing metaclass, not the name of a new one. Anyone who says the keyword is real is right; anyone who says the metaclass does not exist is also right; and Message is a production name that never becomes a class.

Two further things exist under the same name, which is what makes it such reliable bait:

  • Flows::Message, an abstract flow def in the shipped Systems library, described there as “the base type of all FlowUsages”. Flows::Flow specializes it directly, and Flows::SuccessionFlow specializes Flows::Flow in turn. This is a library type, not a metaclass.
  • Transfers::MessageTransfer, a KerML library interaction, which FlowTransfer is declared disjoint from. Also a library element.

So the way to think about message is as one of the three kind keywords for a flow usage, alongside flow and succession flow (clause 7.16.2). A message differs from a streaming flow in what it identifies at its ends: a flow names an out feature of the source and an in feature of the target, whereas a message names the source and target events between which a transfer may happen. The { isAbstract = true } in the production above is why a message is always abstract whether or not you write abstract.

package MessageExample {
    attribute def ControlSignal;

    part def Vehicle {
        part controller {
            event occurrence sendControl;
        }
        part engine {
            event occurrence receiveControl;
        }

        message throttleCmd of ControlSignal
            from controller.sendControl
            to engine.receiveControl;
    }
}

The declaration parts are all optional, and this is the general shape:

message [<name>] [of [<payloadName> :] <PayloadType>] [from <sourceEvent> to <targetEvent>];
message <sourceEvent> to <targetEvent>;

The name, the of payload clause, and the from/to event pair are each independently omissible. The payload clause can also carry a multiplicity, and the : before the payload type is dropped along with the payload name when you omit it, which is why of ControlSignal above needs no colon. The second line is a separate grammar alternative: with no name and no payload you may drop from and write the two events with only to between them. If you omit the payload specification entirely, the message places no constraint on what may be transferred; and if you omit the source and target events instead, you may supply a feature value for the message in their place (clause 7.16.2).

Here is how the forms fare in practice. Every one of them produces a message_usage node in the tree, so the keyword is genuinely recognised in all four cases:

FormGrammar alternativesysml-rs
message <name> from <src> to <tgt>;firstaccepted, no diagnostics
message <src> to <tgt>;secondaccepted, no diagnostics
message of <Type> from <src> to <tgt>;firstaccepted; one info on payload typing
message;first, everything omittedparses, but rejected with “missing source endpoint” / “missing target endpoint”

The first two are the forms worth remembering, and both are exactly what the disputed claim said they were.

Tool note. The last row is the one divergence. A bare message; is grammatically legal – every part of the first alternative is optional – and sysml-rs does build a message_usage node for it, but then raises two errors demanding endpoints. It is a degenerate declaration with nothing to say, so this costs you nothing in practice; it is listed only so the errors are not mistaken for a problem with your model.

For contrast, the streaming-flow sibling. Note what changes: a flow def declares its ends and can constrain the payload by redefining it, and the usage names an out feature on one side and an in feature on the other, rather than a pair of events.

package FlowPair {
    item def Fuel;
    part def FuelTank { out fuelOut : Fuel; }
    part def Engine { in fuelIn : Fuel; }

    flow def FuelFlow {
        ref item :>> payload : Fuel;
        end tank : FuelTank;
        end eng : Engine;
    }

    part def Vehicle {
        part tank : FuelTank;
        part eng : Engine;
        flow supply : FuelFlow from tank.fuelOut to eng.fuelIn;
    }
}

FlowDefinition, FlowUsage and SuccessionFlowUsage are all real metaclasses, unlike Message – which is why the flow rows in the table above carry class names and the message row does not.

Names that do not exist

Each of the following is a plausible-sounding name that is not a metamodel class. They are listed rather than omitted because they circulate in tutorials, in tool output, and in earlier drafts of this book, and a confirmed negative is more useful than silence. Every one was checked against Kerml-Vocab.ttl, SysML-vocab.ttl, KerML-shapes.ttl, SysML-shapes.ttl, both specification texts, and the reference grammar.

Name you may seeVerdictWhat actually exists
MessageNot a metamodel class – but a real grammar rule nameThe keyword message, normative in clause 8.2.2.16, producing a FlowUsage; plus Flows::Message in the standard library
TraceDoes not exist anywhere in the languageNothing. trace appears only as jazz_am:trace, an OSLC interchange property in the API shapes files – not a SysML relationship and not a keyword
AssignmentNot a metamodel classAssignmentActionUsage
AllocationNot a metamodel classAllocationDefinition and AllocationUsage
TransitionNot a metamodel classTransitionUsage
PerformNot a metamodel classPerformActionUsage
ExhibitNot a metamodel classExhibitStateUsage
IncludeNot a metamodel classIncludeUseCaseUsage
FrameNot a metamodel classFramedConcernMembership
RequireConstraintUsageNot a metamodel classRequirementConstraintMembership, whose kind is require or assume
AssumeConstraintUsageNot a metamodel classas above
CompositionNot a metamodel classFeature::isComposite, a Boolean property. A usage is composite unless you write ref (clause 7.6.3)
PortionNot a metamodel classPortionKind, an enumeration on OccurrenceUsage, written snapshot or timeslice (clause 7.9.3)
OwningFeatureMembershipNot a metamodel classFeatureMembership, which already specializes OwningMembership
MessageTransferNot a metamodel classTransfers::MessageTransfer, a KerML library interaction. FlowTransfer is declared disjoint from it

ReturnParameterMembership and ResultExpressionMembership have also been challenged, and they are the opposite case to Message: both do exist as metaclasses, each with its own dedicated abstract-syntax subclause in the KerML specification (ResultExpressionMembership at KerML 8.3.4.7.7, ReturnParameterMembership at KerML 8.3.4.7.8). See the membership table above, and the worked example below it.

Definition and usage pairs

Most SysML element kinds come as a matched pair: a def that declares a reusable type, and a usage that places one in a context. The definition keyword is always the usage keyword plus def.

DefinitionUsage keywordMetamodel classCovered?
attribute defattributeAttributeDefinitionch05
enum defenumEnumerationDefinition (specializes AttributeDefinition)ch05
item defitemItemDefinitionch05
part defpartPartDefinitionch05
port defportPortDefinitionch05
occurrence defoccurrenceOccurrenceDefinitionreference only
connection defconnectionConnectionDefinitionch06
interface definterfaceInterfaceDefinitionch06
allocation defallocationAllocationDefinitionch06
flow defflowFlowDefinitionch06
action defactionActionDefinitionch07
state defstateStateDefinitionch08
calc defcalcCalculationDefinitionch09
constraint defconstraintConstraintDefinitionch09
requirement defrequirementRequirementDefinitionch10
concern defconcernConcernDefinitionch10
case defcaseCaseDefinitionch10
analysis defanalysisAnalysisCaseDefinitionch10
verification defverificationVerificationCaseDefinitionch10
use case defuse caseUseCaseDefinitionch10
view defviewViewDefinitionch13
viewpoint defviewpointViewpointDefinitionch13
rendering defrenderingRenderingDefinitionch13
metadata defmetadata, or the symbol @MetadataDefinitionch13

That is the complete set. The vocabulary declares exactly one more *Definition class, ConjugatedPortDefinition, and it has no keyword of its own because you never declare one – every port def generates its conjugate automatically, and you reach it as ~<PortDef>.

Two things that look like they belong in this table but do not:

  • There is no package def. Package specializes Namespace, not Definition, so there is no definition/usage split to have. You write package <Name> { ... } and that is the whole story.
  • connect is not the connection usage keyword. The usage keyword is connection; connect introduces the ends. Both of these are valid, and the second is the short form you get when the declaration part is empty:
connection <name> : <ConnectionDef> connect <a> to <b>;
connect <a> to <b>;

The same shape applies to allocations (allocation <name> : <Def> allocate <a> to <b>;, or just allocate <a> to <b>;) and to bindings (binding <name> bind <a> = <b>;, or just bind <a> = <b>;).

Metadata is worth one extra note, because it has two notations that are easy to confuse and only one of them is a @:

@<MetadataDef> [{ <body> }]          // a metadata usage, as a member
#<MetadataDef> <declaration>         // a user-defined keyword, as a prefix

The @ form is a metadata usage attached to the element that owns it, and @ is simply the symbolic equivalent of metadata ... defined by ... (clause 7.27.2). The # form is different in kind: it is a user-defined keyword, placed immediately before the reserved keyword of a declaration, and if the named metadata definition specializes SemanticMetadata it also implies a specialization (clause 7.27.4). So #situation occurrence def Failure; declares an OccurrenceDefinition that implicitly subclassifies whatever situation’s base type names. With semantic metadata you may even drop the language keyword entirely and write #situation def Failure;.

Verifying the examples

Every sysml block in this appendix parses with no errors and no error nodes in the tree. The forms were checked with:

sysml --quiet inspect --no-stdlib --diagnostics --json <file>
sysml --quiet inspect --no-stdlib --cst <file>

The second command matters as much as the first. A construct that is not really in the grammar can still parse without complaint, by being absorbed as an ordinary identifier – so the check is not “did it parse?” but “did a node for this construct appear in the tree?”. For the three examples above, the tree contains message_usage, crosses_clause, return_feature and result_expression nodes, which is what makes them evidence rather than guesswork.

The message example does draw one info-level advisory, that its payload type is not matched by a feature type on its endpoints. That is expected: a message names events at its ends rather than typed ports, so there is nothing there to carry the payload type. The example is structurally the same as the specification’s own in clause 7.16.2.

Tool note. Three spec-legal forms are not yet accepted by sysml-rs, so if you meet them in someone else’s model do not assume the model is wrong.

  • frame <ref>; inside a requirement body is rejected with “Unexpected keyword frame, though the long form frame concern <name> : <Concern>; works. Clause 7.21.2 permits both.
  • verify <ref>; is accepted inside an objective { ... } block but not directly in a verification definition body, where verify requirement <ref>; is required instead. Clause 7.24.2 permits both.
  • #<MetadataDef> as a declaration prefix produces “Syntax error near #.... The # token is recognised, but it cannot yet be attached to the declaration that follows it. The @ metadata usage form is unaffected and parses cleanly.

Source anchors

  • Metamodel vocabulary: references/sysmlv2/SysML-vocab.ttl, references/sysmlv2/Kerml-Vocab.ttlrdfs:subClassOf gives the Specializes column, rdfs:comment the descriptions
  • API interchange shapes: references/sysmlv2/SysML-shapes.ttl, references/sysmlv2/KerML-shapes.ttl – note these carry OSLC properties such as jazz_am:trace that are not language constructs
  • Specification text: references/sysmlv2/derived/SysML-spec-r2025-04.txt, references/sysmlv2/derived/KerML-spec-r2025-04.txt – source of every clause number above
  • Reference grammar: references/sysmlv2/SysML-v2-Pilot-Implementation/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext, plus …/org.omg.kerml.xtext/…/KerML.xtext and …/KerMLExpressions.xtext
  • Shipped standard library, for the spec authors’ own usage: libraries/standard/library.kernel/ and libraries/standard/library.systems/Flows.sysml and Transfers.kerml are where Message and MessageTransfer live