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

Definitions and Usages

In Chapter 2, you built a coffee machine model. Along the way, you wrote things like part def Grinder and part grinder : Grinder without much ceremony. This chapter explains why SysML v2 makes that split, what the different definition keywords mean, and how ownership works when you nest elements inside each other.

If you internalize one design rule from this book, make it this: definitions and usages are different jobs. A definition declares a reusable type. A usage places that type in a specific context. Every modeling decision you make in SysML v2 flows from that split.

Why the Split Exists

Consider the Grinder from Chapter 2:

part def Grinder {
    attribute grindSize : GrindSetting;
}

part def CoffeeMachine {
    part grinder : Grinder;
}

Grinder is a definition. It says: grinders exist, and they have a grind size. It does not say where a grinder lives, how many there are, or who owns one.

grinder is a usage. It says: inside a CoffeeMachine, there is one grinder, and it plays the role called grinder.

This separation is what makes the model reusable. Suppose you are modeling a coffee roastery that has a separate grinding station:

part def GrindingStation {
    part grinder : Grinder;
    part spareGrinder : Grinder;
}

The same Grinder definition appears in two completely different contexts – once inside CoffeeMachine, twice inside GrindingStation. The definition did not change. Only the usages differ.

Without this split, you would have to copy the grinder’s properties into every place it appears. Change the grind size attribute, and you would have to find and update every copy. The definition/usage pattern gives you a single source of truth.

The Definition Keywords

SysML v2 has several definition keywords, each signaling a different kind of thing. You have already seen three of them in Chapter 2. Here they are together:

part def – Structural Components

A part definition describes something you can assemble into a structure. Parts have spatial or compositional relationships with their containers. The grinder is inside the machine. The brewer is inside the machine. These are parts.

part def Grinder { ... }
part def Brewer { ... }
part def WaterTank { ... }
part def CoffeeMachine { ... }

Use part def when the thing you are describing is a component that belongs to an assembly. If you can point at it in a bill of materials or a physical breakdown, it is probably a part.

item def – Things That Flow

An item definition describes an identifiable thing the system acts on over time, without requiring that the thing perform actions of its own (SysML §7.10). Items flow through the system, get consumed, get produced, or get exchanged.

item def Water;
item def CoffeeBeans;
item def BrewedCoffee;

Water is not a part of the coffee machine. You do not bolt water onto the frame. But water flows into the tank, gets heated by the brewer, and comes out as brewed coffee. Modeling it as an item tells reviewers: this is something the system processes, not something it is made of.

Parts and items are not rival categories. A part definition is a kind of item definition (SysML §7.11), so every part can be treated as an item when that is the useful view – an engine flows down an assembly line as an item, then goes into a vehicle as a part. Choosing part def picks the primary framing; it does not forbid the other one.

The distinction becomes important when you add behavior in Chapter 7. Actions consume and produce items. Connections in Chapter 6 can carry items between ports. The item keyword sets up these downstream patterns.

attribute def – Properties and Value Types

An attribute definition describes a measurable or configurable property. You used attribute usages throughout Chapter 2 (grindSize, waterTemp, brewPressure), and you also defined one attribute type with enum def GrindSetting.

You can also define custom attribute types explicitly:

attribute def Temperature {
    attribute value : Real;
    attribute unit : String;
}

This defines Temperature as a structured value with a numeric part and a unit. You could then use it:

part def Brewer {
    attribute waterTemp : Temperature;
    attribute brewPressure : Real;
}

Use attribute def when you need a value type that has internal structure. For simple scalar properties, you can type attributes directly with Real, String, Integer, or Boolean from the ScalarValues library.

When to Use Which

KeywordWhat it modelsChapter 2 examples
part defStructural componentGrinder, Brewer, WaterTank, CoffeeMachine
item defThing that flowsWater, CoffeeBeans, BrewedCoffee
attribute defStructured value type(GrindSetting used enum def)
enum defFixed set of valuesGrindSetting

If you are unsure, ask: “Is this thing a component of the assembly?” If yes, part def. “Does it flow through or get consumed?” If yes, item def. “Is it a measurable property?” If yes, attribute def or a scalar type.

You will meet more definition keywords in later chapters – action def for behavior in Chapter 7, state def for operating modes in Chapter 8, requirement def in Chapter 10. They all follow the same <keyword> def <Name> pattern.

How tools render this distinction

The SysML v2 graphical notation gives the def-vs-usage split a visual cue: definitions render with sharp corners, usages render with rounded corners. The same model appears as part def Grinder (a sharp-cornered box) and part grinder : Grinder (a rounded-cornered box) on every conformant diagram. You will see the convention applied throughout the diagram fixtures in this book and in any other SysML v2 tool you use.

Usages: Placing Types in Context

Every definition keyword has a corresponding usage keyword. You drop the def:

part def Grinder { ... }       // definition
part grinder : Grinder;        // usage

item def Water;                // definition
item water : Water;            // usage

attribute def Temperature;     // definition
attribute temp : Temperature;  // usage

A usage always answers three questions:

  1. What kind? The keyword (part, item, attribute).
  2. What name? The usage name (grinder, water, temp).
  3. What type? The definition after the colon (Grinder, Water, Temperature).

The name is how you refer to this particular instance within its context. The type links back to the definition. A reviewer looking at part grinder : Grinder knows immediately what kind of thing it is and where to find its properties.

Untyped Usages

You can write a usage without a type:

part def CoffeeMachine {
    part grinder;
}

This is syntactically valid. But it tells a reviewer nothing about what kind of grinder this is. There is no link to a definition, no properties to check, no way for a tool to validate that the usage makes sense. Treat untyped usages as temporary scaffolding. Always add a type before the model goes into review.

Reuse: One Definition, Many Usages

The real power of the definition/usage split shows up when you reuse definitions across contexts. Consider a company that makes two coffee machine models:

package CoffeeMachineLineup {
    import CoffeeMachineDomain::*;

    part def HomeMachine {
        part grinder : Grinder;
        part brewer : Brewer;
        part waterTank : WaterTank;
        attribute serialNumber : String;
    }

    part def OfficeMachine {
        part grinder : Grinder;
        part brewer : Brewer;
        part waterTank : WaterTank;
        part secondBrewGroup : Brewer;
        attribute serialNumber : String;
    }
}

Both machines use the same Grinder, Brewer, and WaterTank definitions from the CoffeeMachineDomain package you built in Chapter 2. The OfficeMachine happens to have a second brew group, but it reuses the same Brewer definition for both.

If you later add a descaleCount attribute to Brewer, both machines get it automatically. You do not touch HomeMachine or OfficeMachine at all. The definitions are the single source of truth; the usages just point at them.

This pattern also makes the model reviewable. When someone new reads part secondBrewGroup : Brewer, they can look up Brewer once and understand every place it appears. No hunting through duplicated property lists to check if they are all consistent.

Ownership and Membership

When you write an element inside another element’s braces, you are doing more than indenting text. You are declaring an ownership relationship.

part def CoffeeMachine {
    part grinder : Grinder;
    part brewer : Brewer;
}

The grinder usage is owned by the CoffeeMachine definition. This is called membershipgrinder is a member of CoffeeMachine. Ownership has consequences:

  • Scope. The name grinder is visible inside CoffeeMachine. Code outside CoffeeMachine must use a qualified name like CoffeeMachine::grinder to refer to it.
  • Lifecycle. A part or item usage declared like this is composite, and the values of a composite usage cannot exist after the instance that features them ceases to exist (SysML §7.6.3). Destroy a CoffeeMachine, and its grinder goes with it.
  • Containment. Composite parts are inside their owner, structurally. This is what makes CoffeeMachine a composite: it contains its parts rather than merely knowing about them.

Ownership forms a tree. The package owns the definitions. Each definition owns its members. Each member might own further nested elements. This tree gives the model its structure and determines how names resolve.

Nesting Deeper

Ownership can go several levels deep. Suppose the grinder has an internal motor:

part def Motor {
    attribute powerRating : Real;
}

part def Grinder {
    attribute grindSize : GrindSetting;
    part motor : Motor;
}

Now the ownership tree looks like this:

CoffeeMachineDomain (package)
  Grinder (part def)
    grindSize (attribute)
    motor (part)
      powerRating (attribute)
  CoffeeMachine (part def)
    grinder (part) : Grinder
    brewer (part) : Brewer
    ...

Each element has exactly one owner. The motor usage is owned by Grinder. The grinder usage is owned by CoffeeMachine. The Grinder definition is owned by the CoffeeMachineDomain package. There is no ambiguity about where anything lives.

Composite vs. Reference Usages

Every part and item usage you have seen so far is composite – its values belong to the instance that features them and cannot outlive it. But sometimes you need to refer to something without containing it.

Consider a maintenance log that records which grinder was serviced:

part def MaintenanceRecord {
    attribute date : String;
    ref part servicedGrinder : Grinder;
}

The ref keyword says: this usage refers to a Grinder that exists somewhere else. The MaintenanceRecord does not contain a grinder. It just points at one.

Without ref, writing part servicedGrinder : Grinder makes the usage composite – the maintenance record would contain a grinder. That is clearly wrong. A maintenance record is a data entry, not a physical container for machine parts.

The distinction has teeth in the specification, not just in style. Values of a composite usage cannot also be values of another composite usage unless both sit on the same featuring instance (SysML §7.6.3) – a physical grinder is inside exactly one machine. Reference usages carry no such restriction, which is exactly why a record can point at a grinder some machine already contains. It is also why a bill-of-materials rollup counts composite usages and skips references.

Two kinds of usage are referential whether or not you write ref:

  • Attribute usages. A value has no independent existence to contain, so attribute grindSize : GrindSetting is always referential.
  • Directed usages. Anything declared in, out, or inout – including the items inside the port definitions of Chapter 5 – is always referential.

Use ref when the relationship is “knows about” rather than “contains.” We will revisit reference usages when we cover connections in Chapter 6, where they play a larger role.

The Pattern Behind the Pattern

At this point, you have seen the definition/usage split applied to parts, items, and attributes. The pattern is always the same:

<keyword> def <Name> { <members> }     // definition
<keyword> <name> : <Name>;             // composite usage
ref <keyword> <name> : <Name>;         // reference usage

This regularity is intentional. Every new SysML v2 concept you encounter – actions, states, requirements, constraints – follows this same structure. Once you can read part def and part, you can read action def and action, state def and state, requirement def and requirement. The keywords change; the pattern does not.

What Comes Next

You now understand the core modeling pattern of SysML v2: define a type, use it in context. You know the difference between parts (structural), items (flow), and attributes (values). You know that nesting creates ownership, and that ref makes a usage referential so it can point at something without containing it.

In Chapter 4, you will split the coffee machine model across multiple files, using packages and imports to organize definitions so that teams can work on different parts of the model independently.

Common Mistakes

Using part def for everything. Not every concept is a structural component. Water flowing through a brewer is an item, not a part. A temperature reading is an attribute, not a part. Using the right keyword communicates intent and enables correct downstream analysis.

Duplicating definitions instead of reusing them. If HomeMachine and OfficeMachine both need a brewer, define Brewer once and use it twice. Do not create HomeBrewer and OfficeBrewer with identical properties. Specialize only when behavior or structure genuinely differs – Chapter 12 covers how.

Forgetting ref on non-containing usages. If a MaintenanceRecord has part servicedGrinder : Grinder without ref, the model says the record physically contains a grinder. This is a modeling error that tools may not catch as a syntax problem – it is a semantic mistake. When the relationship is “refers to” rather than “contains,” always use ref.