Advent of SysML v2 | Lesson 5 – Modifiers and Multiplicities

Hello and welcome back to the Advent of SysML v2 – a daily, hands-on mini-course designed to bring you up to speed with the new SysML v2 standard and the modern Syside tooling that makes you productive from day one.

By the end of this lesson, you will:

  • Learn about different modifiers in SysML
  • Learn how to use multiplicities

If you want to dive deeper into the world of SysML v2, check out The SysML v2 Book, where this topic is also discussed in more detail.

Abstract and Concrete Types

You have already seen the “abstract” keyword in some of the previous lessons. The time has come to learn its precise meaning.

Both definitions and usages can be either abstract or concrete. The default is concrete, even if you specialize an abstract type. Abstract types are declared with the “abstract” modifier.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package AdventOfSysMLv2_Day5 {
abstract part def CargoBay;
part def MagicalCargoBay specializes CargoBay;

part def SantaSleigh {
abstract ref part reindeer : Reindeer[9];
ref part dasher subsets reindeer;
ref part dancer subsets reindeer;
ref part prancer subsets reindeer;
ref part vixen subsets reindeer;
ref part comet subsets reindeer;
ref part cupid subsets reindeer;
ref part donner subsets reindeer;
ref part blitzen subsets reindeer;
ref part rudolph subsets reindeer;
}

part def Reindeer;
}

An abstract definition is a partial “blueprint” that is not yet ready for instantiation. More formally, every instance of an abstract definition must also be an instance of a more special concrete definition. For example, the abstract definition “CargoBay” cannot have an instance that is not also a “MagicalCargoBay” (or any other concrete specialization of “CargoBay”, if there is more).

An abstract usage works similarly but is perhaps even more useful. An abstract usage cannot have a value that is not also a value of a concrete subset. This way, we can essentially model a derived union – the abstract usage will be exactly the union of all of its subsets, since it cannot have any other value. 

This provides a convenient way to “enumerate” elements in singleton subsets. If you look at line 6, the usage “reindeer” is abstract, and its subsets are listed from lines 8 to 16.

Takeaway: 

  • Use abstract definitions if your type is just a skeleton and meant to be refined.
  • Use abstract usages if you want to union all their subsets and only have values that are present in at least one subset.

Composite and Referential Usages

You also saw the keyword “ref” before. It is short for referential. Usages can be either composite or referential. The default is generally composite, but there are many special usages that are always referential. Referential usages are declared with the “ref” modifier.

1
2
3
4
5
6
7
package AdventOfSysMLv2_Day5 {
part def SantaSleigh {
part cargoBay : CargoBay;
ref item santa;
}
abstract part def CargoBay;
}

A composite usage means that the composing type owns the value; it is an integral constituent of it. This means two things:

  • Single ownership: Values of a composite usage cannot be values of another composite usage, unless they are owned by the same thing. For example, the cargo bay of a sleigh cannot be the cargo bay of another sleigh, but can be one of the compartments of a sleigh (if we had another composite part usage).
  • Destruction: If something is the value of a composite usage when the lifetime of the composing thing ends, it also ends. In other words, when the sleigh ceases to exist, the cargo bay will also do so. The other way is equally true: the sleigh cannot cease to exist until the cargo bay exists.

In contrast, a referential usage is just a reference to a value, with none of the above consequences.

Takeaway: 

  • Use composite usages if the type should own the values. This is probably the case when the values are an integral part of the whole, or their lifetime is related (for example, an action should not survive the part that performs it).
  • Use a referential usage if something else owns a value, but you also need to refer to it.

Variables and Constants

A variable is called a variable because its value may vary. In other words, they can be described by a function of time. Almost every structural usage in SysML is a variable, except for behaviors and features of attributes (we will discuss these in later episodes). However, some variables are not intended to change over time. These are constant variables, which can be declared with the “constant” modifier. A constant is still a variable. It just does not change its value, and it cannot be changed externally either.

Examining the example, we can see two attributes within Reindeer.

1
2
3
4
5
6
7
package AdventOfSysMLv2_Day5 {
private import ScalarValues::*;
part def Reindeer {
attribute energyLevel : Real;
constant attribute noseColor;
}
}

The attribute “energyLevel” in line 4 can and should change. However, “noseColor” is declared as a constant attribute, so it will never change throughout the lifetime of the reindeer.

Takeaway: 

  • Use a constant usage when the value is not supposed to change or be changed.

Multiplicities

One of the most important features of a usage is its multiplicity. It specifies how many values an instance of the owning type may have for that usage (at any given time, if it is a variable). For example, each sleigh may be pulled by nine reindeer. It is usually given as a range with a lower and an upper bound, enclosed in square brackets, separated by two dots. However, the lower bound can be omitted. In this case, it is considered equivalent to the upper bound. Furthermore, the upper bound can be star (“*”), which means there is no upper bound and there can be an unlimited number of values. The multiplicity can be placed anywhere after the name of the usage (immediately after the name, after the type, or after any subsettings/redefinitions).

One important thing to learn is the default multiplicity (where none is specified explicitly). By default, an unconstrained multiplicity is [0..*]. However, if all the following conditions are true, the default is [1..1]:

  1. The usage is an attribute usage, an item usage (including a part usage, except when it is a connection usage), or a port usage (we will cover these in later episodes).
  2. The usage is nested in a definition or another usage (not a package).
  3. The usage does not have any subsettings or redefinitions (which would make it inherit the multiplicity).

You can observe some examples in the following model.

1
2
3
4
5
6
7
8
package AdventOfSysMLv2_Day5 {
part def SantaSleigh {
ref item payloads [0..10];
ref item passengers [1..*];
abstract ref part reindeer : Reindeer[9];
ref part dasher subsets reindeer;
}
}

The usage “payloads” in line 3 has 0 to 10 values, while there is at least one passenger according to line 4. The usage “reindeer” in line 5 has to have exactly 9 values because no lower bound was specified, so it is equivalent to the upper bound, which is 9. 

The usage “dasher” does not have a multiplicity. It is a part usage, nested in a definition… but it has a subsetting! This means that its default multiplicity is still [0..*], contrary to our intent that it should be a singleton set. The moral of the story is that it never hurts to be explicit when it comes to multiplicities!

Takeaway: 

  • Use a multiplicity to specify the number of values a usage can have.
  • Be aware of the rules governing the default multiplicity, and always be explicit when you subset something. Otherwise, the multiplicity will be determined by the subsetted usage.

Challenge for Tomorrow

Now that you know almost everything about definitions, usages, and specializations, it is time to do some more serious designing on Santa’s sleigh. Go to Syside Cloud and do the following tasks:

  1. Model the cargo bay’s definition such that it can be either an ordinary cargo bay that may hold one payload that is a bottomless gift bag, or a magical cargo bay that can hold an arbitrary number of ordinary bags. We want to be able to access the payload of the cargo bay regardless of the configuration.
  2. Add composite or referential usages to the SantaSleigh definition to model:
    • exactly two runners, enumerated as the left runner and the right runner
    • Mrs. Claus (Santa has to communicate with her during work)
  3. Add attributes to the Reindeer definition to describe the weight and the name of a reindeer (use constant if applicable).
  4. Review the multiplicities in the whole model and specify it whenever the default is not suitable.

Summary

In this episode, you learned about modifiers for definitions and usages, as well as multiplicities. With this, you have finished the foundations and can move on to learn the different concepts supported by SysML v2. If you haven’t yet done so, it is now time to go to Syside Cloud to do the challenge – and don’t forget to come back tomorrow for another episode of the Advent of SysML v2!

Cookies