Constants and literals

Before laying out the solution of how these are handled in Scrall, it may be useful to understand the reasoning leading up to our unconventional solution.

Most programming languages allow the expression of literal values, named values and variables. A literal value might be 3.14 or "Untitled". A named value, or constant, could be PI or MAXINT.

It is bad form to mix literal values in action language. In practice, model developers do it anyway, but with a few notable exceptions, there are safer and better alternatives.

Values that are special in the context of some application like, let’s say, 7, 270 degrees, 2500 psi, etc. are almost always bad ideas for the same reasons they are bad ideas in code. Here are just a few common problems.

Hard to find

A critical value like 350 degrees may need to be changed to 425 degrees someday. If it is in an attribute of some specification class it will be easy to find. Furthermore, the purpose of that limitation should be documented in its attribute description. But if instead the value just pops up in the action language somewhere, how will we find it? And why was that particular value selected?

Hard to ensure uniformity

Change 2500 psi in one place, but is it used somewhere else? Where? What if it is used in three places but you only change it in two. What’s the worst that could happen? By putting the value in the class model you can ensure that the value need only be updated in one location.

Time consuming and error prone to change

When you change 350 degrees to 425 degrees in an activity you are changing the model itself, not the instance population. So now you have to recompile, retest and reintegrate the portion of the model that you modified. If, on the other hand, you change the value of the Heating Specification.Standard bake temperature attribute for some instance you are not changing the model itself, just some data in its population. In a running system, you can effect this change by issuing a runtime edit command or reloading an initialization file without any need to recompile.

Data is best modeled in the class model

Basically, use the right tool for the right job.

There are, of course, times when you want to perform a computation with a mathematical constant. A value like pi is typically outside the subject matter of your domain, so it doesn’t really belong in the class model. By the same reasoning, though, it really shouldn’t be defined in the action language either.

So we do need to find a way to define and use mathematical constants as well as special values like “” (empty string). And while a value like, pi doesn’t change, the desired approximation might. We also not that the boolean true and false are generally quite helpful.

And then there is also the question of values for enumerated data types. It wouldn’t be unreasonable to have logic in an activity that branches based on the current landing gear status like the following:

if /R1/Landing Gear.status = .retracted
   // do x
else
   // do y

And then there’s the issue of instance creation. How do you create a new instance without supplying values for each of its attributes?

Color = “Blue”
Doors = 4
Speed = 0.0
Driver = ~  // No driver initially

You could argue that the initial attribute values could be gathered from a related specification class such as Car Specification with attributes like Initial color, etc. But sometimes the specification class solution can be a bit of overkill, especially in smaller applications.

So while there are important exceptions, it is STILL bad form to bury a literal value like 15.2 deep in some activity. And if the action language allows it, bad or lazy modelers are going to keep doing this kind of thing.

Solution: No literals in Scrall (pretty much)

Since there are other ways to handle the exceptional cases, literal values are pretty much illegal in Scrall. In particular, a statement like this…

desired temp = 350.0  // ERROR!

will trigger a fatal error. We’ll return to this example with a better solution, but first let’s take into account all the other cases and exceptions.

Instance attribute creation values

First, consider new instance creation. The UML standard already suggests a solution with the initial value field on the class diagram. This is a value applied by default to the attribute of any new instance. This moves default initial values out of the action language and into the class model. When an instance is created, the model execution architecture will use those initial values if no other value is specified.

For example, if you want to ensure that every instance of Dog has its Dog.Breed attribute initialized with the value “Collie”, then just put that value in the appropriate class model’s initial attribute value definition. Then when you create a new instance of Dog, omit the Breed attribute like so:

new dog .= *Dog( Name: in.Supplied name ) &/owns/R1

And the breed will be set automatically to "Collie" since it wasn’t specified. Note that the rightmost part of the action links the newly created dog to the local instance, presumably Dog Owner, on the R1 association.

Boolean values

The values true and false are keywords in Scrall. That said, most of the cases where you might use them have been eliminated. That’s because you can use the set and unset operations defined on the Boolean data type.

Let’s say we have a boolean Shuffle attribute in a music application which either does or does not shuffle the play order in a song list.

song list.Shuffle.set // now it's value is true
song list.Shuffle.unset // now it's value is false
if (song list.Shuffle) ...  // You don't need a literal to test the value

But, if you want, you can do this:

song list.Shuffle = true
if (song list.Shuffle == true) ...

There are other situations where you want the boolean value keywords such as:

return( true )

Selected special values

For zero and other special values we will use a thing called a selector combined with an alias.

Selector operations

A selector is an operation defined on a data type that selects out a particular value from the values defined by that type. Let’s say that we want to select the number 2 from the system defined data type Integer. We could then define a selector operation named “2” invoked like this:

x = Integer( 2 )  // Won't work in Scrall

You can read more about the concept of a selector in Type Inheritance and Relational Theory, C.J. Date, O’Reilly 2016.

In principle there would be a selector operation available for every value defined by the data type. To avoid the problems with embedding literal values in action language, these selectors will be prohibited in Scrall.

Selector alias

Instead, we will provide an aliasing system to grant action language access to a small subset of needed selectors.

Let’s say, for example, that you have an algorithm that computes the perimeter of a circle. So you need both pi and 2.

Somewhere in the data type definition language (not Scrall) you will be able to create the necessary aliases for the selectors you need to access:

_2 alias Integer( 2 ) // Not Scrall
_pi alias Real( 3.14159 ) // Not Scrall

All aliased values must begin with an underscore _ character. So don’t use the _ symbol as the first character of your model element or variable names.

Other than the basic theory as defined in C.J. Date’s book referenced earlier, no official data type language to use with xUML has been determined yet. But you need some way of defining your data types. The “Not Scrall” comments just mean that we are using some psuedo-code data type specification language for now to make the related definitions.

So this could be legal in scrall:

Perimeter = _2 * _pi * radius  // Okay, this IS Scrall

In reality, you are much more likely to take advantage of a math library:

Perimeter = MATH.Circle perimeter( radius )  // Also Scrall

Once again showing that you probably don’t need any special selectors anyway.

The same principle works with non-mathematical values. Let’s say that you want to create all new instances of Folder with the string “Untitled”.

_untitled alias String( "Untitled" ) // Not Scrall

Now you can do:

folder name = _untitled

Though, it is probably a better idea to not do this and just have an attribute Folder specification.Default new name or put Folder.Name = “Untitled” on the class diagram. Keep in mind that the specification class solution puts the default new name into the instance population with the advantages discussed above.

You don’t really need to do this for an empty string “”. Just use the a standard operation defined on the string data type like this:

customer name.clear  // Sets name to ""

Enumerated values

Since enumerated values are generally limited in number and are often used to test cases, it makes sense to express them in actions.

A type might be defined such as Valve State with values { open | closed }

And then a variable position of that type would be used like so:

switch( position )
   .open : Close -> target valve  // send event to a valve object
   .closed : Open -> target valve

Note that enumerated values are always prefaced with a . symbol. In circumstances where the data type cannot be inferred from context, the data type must precede the value like this: Valve State::closed.