5.2.2. Assignment statements for roles

Below, we’ll find that assignment operators on roles take one or more arguments, that specify what they operate on. For example, in the case of the remove operator its first argument says what we want to have removed automatically. These arguments can be arbitrary expressions – as long as they select roles of the same type as the Object of the Perspective. The system, after all, must operate within the limits set for the user that it works on behalf of!

Implicitly, we give the user that the system carries out an automatic effect for, the role- and property verbs required to do so.

5.2.2.1. Remove

Let’s consider the situation where we have some instances of a role that we want to remove from their context. We have selected them with a query, <roleExpression>:

remove <roleExpression>

Remember, <roleExpression> is a query applied to the current context instance. For example, this could be such an expression:

filter SomeRoleType with Completed = true

This query will select some instances of SomeRoleType in the current context instance. If we prepend the keyword remove to that expression, all those role instances will be removed from the current context instance.

This works on any context, because role instances are bound to a context. We need not say from which context we want to remove them. So in order to remove role instances from an embedded context, we’d write for example:

remove filter AContextRole >> binding >> context >> AnotherRole with Completed = true

We select a context role, move to the context that is bound in it, move to one of its roles and filter it like before. As before we end up with a number of role instances: these will be removed from the embedded context.

What if we want to remove a role that has been added to a Database Query Role? In order to enable the system to decide whether removing the (external) role instance is allowed, it needs to know the Calculated Role type that it should be removed from. So we get:

remove <roleExpression> from RoleType
5.2.2.2. CreateRole

Create a new role instance in this way:

createRole RoleType

Here RoleType is not a query, but the identifier of the role we want to create. We can use an unqualified name but it will have to resolve in the type of the current context. The new role instance is attached automatically to that context. In that sense, createRole is an assignment statement, too.

We can also create a role instance in another context:

createRole RoleType in <contextExpression>

<contextExpression> selects one or more context instances. RoleType now has to resolve in the type of those instances.

5.2.2.3. Move

Usually, when we add a role instance, we create it at the same moment. However, it is possible to move role instances from one context instance to another. Then we use the move operator:

move <roleExpression>

This removes the selected instances from their origin context and adds them to the current context.

Note that if <roleExpression> selects instances in the current context, this statement does not change state!

To move to another context, we use an extra clause: move <roleExpression> to <contextExpression>

Again, in order to make this useful, <roleExpression> should select from another context than that identified with <contextExpression>. Notice that <contextExpression> can only select a single context.

5.2.2.4. Delete

Sometimes we just want to remove all instances of a role. Then we use delete:

delete role <roleType> [from <contextExpression>]

Select the instances to be removed. Optionally, to select from another context, add the from <contextExpression> clause. Be careful with deleting the instances of a Database Query Role: all instances that are not bound to some other role will be removed from the users Bubble!

To remove all values of a property, use a slightly different syntax:

delete property PropertyType [from <roleExpression>]

Notice that we do not provide a query to select instances. We just want to remove all values of the property. By default, we remove them from the current object set (see Object of the Perspective below). To remove from another role, add a clause:

delete property PropertyType from <roleExpression>

Obviously, PropertyType has to resolve in the type of roles selected by <roleExpression>.

5.2.2.5. Bind

To fill a role with another role, use bind (when A fills B, we say that B is bound to A. A is the binding; B is the binder). Bind like this:

bind <binding> to RoleType

createRole RoleType filledBy <binding>

Here, <binding> selects instances of a role (the bindings) whose type must be equal to, or more specialized then, the possible bindings of RoleType. A new instance of RoleType will be constructed automatically (the binder) and attached to the current context.

To bind in another context, add a clause:

bind <binding> to RoleType in <contextExpression>

Again, RoleType should resolve in the type of the instances selected by <contextExpression>.

If RoleType happens to be functional, <binding> must evaluate to a single role instance as well. Notice that <contextExpression> may evaluate to multiple contexts; we just bind in all those contexts.

5.2.2.6. Bind_

The variant bind_ can be used to bind an instance of a role in a previously existing instance of RoleType:

bind_ <binding> to <binder>

The first expression (<binding>) selects a role instance that is going to be bound to the role instance selected by the second expression (<binder>). Notice the singular: this operation only works on singletons.

If we allowed more bindings and binders, it would be unclear what should be bound to what.

Obviously, the binder must be legally able to attach to the binding. That is, the possible bindings of the binder must be equal to or more general than the type of the binding.

To bind in another context, just select binders in another context.

5.2.2.7. Unbind

The inverse of bind is unbind. Notice that unbind does not remove anything. Both the binder and the binding remain attached to their contexts.

unbind <roleExpression>

Here, <roleExpression> selects role instances as before. But do we consider them as binders, or bindings? Both are possible. By convention, we choose them to be bindings (fillers) and thus we release them from the roles that bind them (filled by them).

Notice the plural. A role can be bound many times, in many different other roles. By just using an unqualified unbind, we break all bonds that this instance has. Usually, we want to be more selective and this we achieve with another clause:

unbind <binding> from RoleType

Now, we just release the instance from a particular type of binder. Still, this is across all instances of the context with that type of binder. We can’t be more selective with unbind, but we can with unbind_.

On removing the last binder of an external role, the context it belongs to may be removed, too! This process can cascade recursively to nested contexts.

5.2.2.8. Unbind_

Remember that bind_ allowed us to select roles that become a binding and a binder respectively. Similarly, with unbind_ we select a role that is a binder and a role that is a binding and break them apart:

unbind_ <binding> from <binder>

As with bind_, this only works with singletons.

There is another use case for unbind_. It is possible to bind a role instance to more than one other role instance, of different types. This enables us to create role instances as combinations of property packages, as it were: think of a role at the pharmacy that you’ll fill both as patient and as bank account holder. Unbind_ allows us to pick those multiple bindings apart. We can just remove, say, the bank account role from the pharmacy client role.

As with unbind, on removing the last binder of an external role, the context it belongs to will be removed, too! This process will cascade recursively to nested contexts.

5.2.2.9. ‘missing’ statement types: add and set

One might expect an operator add, to add role instances to a context. However, just where would these instances come from? We don’t need add for creating instances, because createRole ‘adds’ the created instance to the context anyway. The only possible source for the right kind of instances would be from another context than the current. However, for this we have the move operator. Notice also that a role instance can only be attached to one context instance. So to move, we have to detach and re-attach somewhere else, preferably in a single transaction. This is precisely what move accomplishes. By omitting the add operator, we protect the modeller from mistakes without compromising what he can express.

A set operator would replace the current instances of a role with a new set. There are use cases for this operator, but these can always be programmed by a combination of delete and move or delete and createRole.