Create Synchronization_Language authored by Christopher's avatar Christopher
Synchronization Language
===
# GENERAL INFORMATION
- Jede Regel wird zu einer oder mehrerer Rollen in einer oder mehreren Compartments und bekommt noch einen Präfix Delete* Create* Synchronize*
- Damit haben alle Regeln auf jeden Fall schonmal einen einmaligen namen
- Andere Regeln wie Helper Regeln bekommen einen anderen Präfix und können als eigenes Compartment mit eigenen Rollen betrachtet werden
- Beim Erstellungsregeln werden über das Synchronisationscompartment Verlinkung zwischen den Teilprojekten erzeugt, d.h. sobald es eine Regel gibt die Gleichheit zwischen Objekten spezifiziert oder das erstellen Managed, werden automatischen die Verlinkungen auf Instanzebene mit erstellt. Diese müssen dannach nicht nochmal neu in Regeln spezifiziert werden
- Sobald sich die Synchronisationsregeln oder anderen Regeln ändern können diese zur Laufzeit ausgetauscht werden
- Falls die Namen identisch bleiben müssen nur die Regeln neu geladen werden und ersetzen sich gegenseitig
- Synchronization wird dann wieder auf den Punkt hergestellt und neue Modelle falls sie dazugekommen sind gleich mit integriert
- Möchte ich den Fall abbilden können, dass ich ein Element in einem Modelverbund löschen aber nicht die Verknüpften Elemente mitlösche (Nein: da dies zu unkontrollierten Problemen führt => maximal woanders als gelöscht markieren)
- darauf ergibt sich die Frage ob ich feingranulare Regeln überhaupt haben möchte oder ob mich eigentlich nur der Ansatz mit einer Regel die alles abbildet interessiert
# Running Example for this Webpage
- 3 Modelle Families, Persons und SimplePersons
- Konzept einer Person ist in jedem Modell verhanden
- Änderungen von einem Model müssen an die anderen propagiert werden
### Families (Model A)
```
class Family {
lastName: String
father: Member
mother: Member
sons: List[Member]
daughters: List[Member]
}
class Member {
firstName: String
address: String
birthday: Date
familyFather: Member
familyMother: Member
familySon: Member
familyDaughter: Member
}
```
### Persons (Model B)
```
class Person {
fullName: String
birthday: Date
}
class Male extends Person {}
class Female extends Person {}
```
### SimplePersons (Model C)
```
class SimplePerson {
completeName: String
address: String
male: Boolean
}
```
#### PhoneBook (Model D)
```
class PhoneBookEntry {
firstName: String
lstName: String
address: String
telefonNumber: String
}
```
# IDEAS WITH THOMAS
- Regeln sollten umkehrbar sein um gut abzubilden ist jedoch schon in diesem Beispiel nicht machbar
- Families!Member.firstName + ' ' + Families!Family.lastName = Persons!Person.fullName
- e.g., fullName: "Phing Phang Phung" => firstName: "Phing Phang" + lastName: "Phung" or firstName: "Phing" + lastName: "Phang Phung" ???
## Object invariant
```
Objinv (Person, SimplePerson, Family o Member)
with (Member.firstName + " " + Family.lastName, Person.fullName, SimplePerson.completeName)
```
- Problem ist die Unterscheidung von männlich und weiblich, die kann ich hier nicht Abbilden, was natürlich die Problematik mit jeglicher Vererbung wieder mit sich bringt
## Attribute invariant
```
Attinv (Person, SimplePerson, Family o Member)
with (Member.firstName + " " + Family.lastName, Person.fullName, SimplePerson.completeName)
```
- Als Synchronisationsregel möglich jedoch zum Erzeugen nicht ausreichend
- Idee am Ende nur eine Regel Art aus der Synchronisations-, Lösch- und Erstellungsregeln erzeugt werden
# COMPLETE RULES
- Regeln, welche für Synchronization, Löschen und Erstellen verwendet werden können
- Vorteil:
- Kurze Regelschreibweise
- Sobald Elemente in der Regel vergessen werden fällt dies schneller auf
- Nachteil:
- keine feingranuale Spezifikation der Regeln
- Elementtypen werden für Löschen, Erstellen und Synchronisieren immer zusammenbetrachtet
### Complete Rule
- Code Generator muss Erstell-, Lösch- und Synchronisationsregeln aus einer so einer Regel generieren
- Erzeugung von Objekten kann anhand von Sync Regeln abgeleitet werden
- Trennung in primary Regeln und non-primary Regeln
- primary Regeln bestimmen Objekte zwischen Modellen eindeutig
- **Alte Idee:** Erzeugung von Objekten kann anhand der primary Regeln abgeleitet werden (Verkettung der primary Regeln für eindeutige Objekt erkennung zwischen Modellelementen verschiedener Modelle)
- Probleme
- Short Hand notationen für spezial Fälle die immer verwendet werden? **Brauchen wir das wirklich?**
- Grenzen von change Operatoren definieren **in folgenden Beispielen schon mit betrachtet**
#### Rule A
```
"primary" syncRule NamesOfFamilyAndMemberAndPersonAndSimplePerson {
sync
a : Families!Member
b : Persons!Person
c : SimplePersons!SimplePerson
d : Families!Family (a.family==d)
with
//1. normaler Falls
a.firstName + ' ' + d.lastName == b.fullName == c.completeName
//2.1 falls completeName = d.lastName + ',' + a.firstName wäre
a.firstName + ' ' + d.lastName == b.fullName
d.lastName + ',' + a.firstName == c.completeName
//2.2 oder mittels hilfsfunktionen für first & lastName (Ende Dokument)
a.firstName + ' ' + d.lastName == b.firstName + ' ' + b.lastName == c.lastName + ',' + c.firstName
}
```
#### Rule B
```
"primary" syncRule AddressesOfMemberAndSimplePerson {
sync
a : Families!Member
c : SimplePersons!SimplePerson
with
a.address == c.address
}
```
#### Rule C
```
"primary" syncRule BirthdaysOfMemberAndPerson {
sync
a : Families!Member
b : Persons!Person
with
a.birthday == b.birthday
}
```
#### Fälle Primary Rules
- Wenn ich einen Modellverbund habe, wo alle Elemente auf die Regeln zutreffen in der Synchronisation enthalten sind, dann muss ich beim Insert nicht nach schon vorhandenen Elementen suchen, das würde nur bedeuten, dass das Element in dem Model wo es erstellt wurde schon existiert
- Deswegen macht die unterscheidung in primary und non-primary Regeln keine Sinn
- Außer man nutzt Primary Regeln für die integration von neuen Modellen
- **ALT Anfang**
- Fall (i): A (non-primary), B (non-primary), C (non-primary)
- Keine Erzeugung von Objekten in anderen Modellen, möglich da keine Primary Regeln
- Fall (ii): A (primary), B (non-primary), C (non-primary)
- firstName + ' ' + lastName == fullName == completeName (bestimmen die Abhängigkeiten zwischen den Modellen eindeutig)
- Namen als eindeutige Identifikation zwischen den Modellen angesehen
- Fall (iii): A (primary), B (primary), C (primary)
- firstName + ' ' + lastName == fullName == completeName && (address || birthday) (bestimmen die Abhängigkeiten zwischen den Modellen eindeutig)
- Namen in Kombination mit Geburtstag oder Adresse bestimmen die eindeutigen Referenzen zwischen den Modellen
- **ALT Ende**
#### Anmerkungen
- `[a.firstName,d.lastName].join(' ')` wäre umkehrbar zu, a.firstName, d.lastName = syncValue.splitFirst(' ')
- typisches muster von `a.p + 'sep' + a.q` ist schwer zu überführen
- Möglich `a.p+'sep'+a.q <a.changePandQ(syncValue)>`
- Oder im Allgemeinen nicht einfach übersetzen, wie z.B.: `a.p1+':'+a.p2+'.'+a.p3*a.p4`
### Integrate the FeMaleSync
- Female/Male Änderungen in den Modellen:
- im Model Families Verweis umsetzen wenn es von männlich zu weiblich wird
- im Model SimplePersons nur Attribute male neu setzen
- im Model Persons dann eine delete und Insert methode und dann nur case schreiben
- Problem:
- Was mache ich beim Löschen mit Werten die vorher nie angefasst wurden?
- Beispiel: Ändern einer Person im Persons Model von Male zu Female
- Benötigen einer Kopie die den Zustand nach dem Löschen und neu erstellen wieder herstellt
- Zwischen Werte irgendwie Abspeichern, jedoch sind einige Werte von der Person in keiner Regel definieren
- Lösung: Person zwischen speichern und dann, neue Person mit alten Daten befüllen
```
syncRule FeMaleSync {
sync
a : Families!Member
b : Persons!Person
c : SimplePersons!SimplePerson
d : Families!Family (a.family==d)
with
//Idee 1: instance of
a.isFemale() == not c.male == b.isInstanceOf[Persons!Female]
//Idee 2: case statement [syncValue as universal useable variable]
a.isFemale() == not c.male == case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})
//Idee 3: everything case statement
case(a, {syncValue==a.isFemale()}) == case(c, {syncValue==not c.male}) == case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})
do
a.switchGender(syncValue) //helper Function
b.switchMaleFemale(syncValue) //helper Function
c.male <- syncValue or c.switchMale(syncValue) //helper Function
}
Other Ideas OLD:
a.isFemale<a.switchGender(syncValue)>
not c.male<syncValue>
b.isInstanceOf[Female]<b.switchMaleFemale(syncValue)> or
case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})<b.switchMaleFemale(syncValue)>
a.f(x) <a.g(y,x)> == y
c.male <- not a.isFemale() == b instanceOf Female
t1 : Persons!Female <- a.isFemale() == not c.male
t2 : Persons!Male <- not a.isFemale() == c.male
a.changeIsFemale(<- c.male == b instanceOf Male)
```
- Anmerkungen:
- `instanceof` ist zwar Boolean aber not (instance of Female) ist nicht sinnvoll.
- Beispiel Operator: `case(b, {true: Persons!Female, false: Persons!Male})`
- General Operator: `case(o, {v_1:Model!Element1, ... v_n:Model!ElementN})` where Model is an arbitrary model and `Element1` till `ElementN` elements in this model. Moreover, $v_1$ till $v_n$ are arbitrary primitive (later object) values.
- Noch generellere wäre $v_1$ könnte $c.age>4 \land c.age<10$ sein, damit könnte ich Phasen oder Altersgruppen in Modell Instanzen synchronisieren
### Hilfs Funktion (Families) Mother<-> Father & Daughter <-> Son
- Anders wäre die Transformation von Persons und SimplePersons zu Families nicht möglich
- Funktion setzt Mütter zu Väter, Tochter zu Sohn und umgekehrt
- Methode müsste aufgerufen werden falls so eine Änderung in Persons oder SimplePersons auftritt
- Problem:
- da diese Änderungen auch in die Family Klasse übernommen werden müssen kann es sein das dort eine Vater Relation überschrieben wird oder eine Mutter Relation überschrieben wird, da es sich um opposite Relationen handeln kann
- Dies würde zu einer nicht mehr handhabbaren Veränderung führen
```
helper context Families!Member def : switchGender (female : Boolean) : Unit =
if female then //female case (set to female)
if self.familyFather.oclIsUndefined () then
if not self.familySon.oclIsUndefined () then
self.familyDaughter <- self.familySon
endif
else
self.familyMother <- self.familyFather
endif
else //not female case
if self.familyMother.oclIsUndefined () then
if not self.familyDughter.oclIsUndefined () then
self.familySon <- self.familyDughter
endif
else
self.familyFather <- self.familyMother
endif
endif;
```
### Hilfs Funktion (Persons) Male <-> Female
- Müsste wie ein Delete und Insert interagieren `self.type <- Person!Female`
- Befehl vielleicht noch ändern nur wie? TODO
```
helper context Persons!Person def : switchMaleFemale (female : Boolean) : Unit =
if female then //female case (set to female)
if self.isInstanceOf[Persons!Male] then
self.type <- Person!Female
endif
else //not female case (set to male)
if self.isInstanceOf[Persons!Female] then
self.type <- Person!Male
endif
endif;
```
### Hilfs Funktion (SimplePersons) male attribute
- Braucht nicht extra eine Hilfsfunktion muss nur Attribute umsetzen
- Befehl vielleicht noch ändern nur wie? TODO
```
helper context SimplePersons!Person def : switchMale (female : Boolean) : Unit =
if female <> self.male then //change if different
self.male <- female
endif;
```
### Integration of PhoneBook Model: extension of syncrules
#### New Rules
```
primary syncRule NamesWithPhoneBookEntry extends NamesOfFamilyAndMemberAndPersonAndSimplePerson{
sync
e: PhoneBook!PhoneBookEntry
with
e.first + ' ' + e.last == b.fullName
}
```
```
syncRule AddressWithPhoneBookEntry extends AddressesOfMemberAndSimplePerson{
sync
e: PhoneBook!PhoneBookEntry
with
e.address == c.address
}
```
- primary Operator, um zu sehen welche Regeln nötig sind um ein Model in die existierende Synchronisation einzubeziehen
- hier wäre nur Model B notwendig, da es das einzige interagierende in der `primary` Regel ist
- Erweiterungsregel könnte als neues Compartment einfach mit eingeladen werden
- Möglich Regel zu neuer großer Regel zu kombinieren und dann mit einmal neu einzuladen (jedoch dann nicht mehr ganz klar, welches Model neu ist, und wie dies gleich in die existierende Synchronisation integriert wird)
### Delete Phone Book Model from Synchronization
- `delete PhoneBook` könnte genutzt werden um ein Model komplett aus der Synchronisation zu löschen
- Regeln würden weiter exisiteren jedoch würde er intern alles davon betroffene ignorieren
# SPLIT INTO 3 RULE TYPES
- Synchronizations-, Lösch und Erstellungsregeln einzeln definieren und dann in dazugehörigen Compartments umsetzen
- Vorteil:
- Feingranulare Spezifikation der Regeln in der Synchronisationssprache
- Element typen können speziell aus dem Löschprozess rausgehalten werden
- Nachteil:
- Mehr schreib Aufwand für Regel Spezifikation
- Sobald Regeln vergessen werden können diese nicht umgesetzt werden
## Synchronization Rules
- 3 Ideen wie Synchronisationsregeln aussehen könnten die 3. ist dabei die vermutlich Eleganteste
- die 2. ist nur abgewandelt zur 1. und eigentlich sinnlos
### Idee 1
- Jede Regel sagt genau welche anderen Objekte sie verändert und sorgt dafür das nicht das gleich Model nochmal angefasst wird
- 1 zu n
```
syncRule syncFirstNameFromMember {
from
a : Families!Member (firstName) //variablen Änderung auf die diese Regel reagieren soll
in
b : Persons!Person (
b.fullName <- a.firstName + ' ' + b.lastName //idee in part darf nur von from part beeinflusst werden und nicht von anderem in part
),
c : SimplePersons!SimplePerson (
c.completeName <- a.firstName + ' ' + c.lastName //darf nicht von b beeinflusst werden
)
}
syncRule syncLastNameFromFamily {
from
a : Families!Family (lastName) //variablen Änderung auf die diese Regel reagieren soll
in
b : Persons!Person (
b.fullName <- b.firstName + ' ' + a.lastName
),
c : SimplePersons!SimplePerson (
c.completeName <- c.firstName + ' ' + a.lastName
)
}
syncRule syncFullNameFromPerson {
from
b : Persons!Person (fullName)
in
a : Families!Member (
a.firstName <- b.firstName
),
d : Families!Family (
d.lastName <- b.lastName
),
c : SimplePersons!SimplePerson (
c.completeName <- b.fullName
)
}
syncRule syncCompleteNameFromSimplePerson {
from
c : SimplePersons!SimplePerson (completeName)
in
a : Families!Member (
a.firstName <- c.firstName
),
d : Families!Family (
d.lastName <- c.lastName
),
b : Persons!Person (
b.fullName <- c.completeName
)
}
```
### Idee 2
- Nachteil Änderungen werden auch im eigenen Model nochmal durchgeführt, da die Funktion syncNames nicht unterscheidet von welchem Element sie aufgerufen wird
- diese Regeln Rufen immer nur die Synchonisationsfunktion auf und bestimmen selbst nur welches Änderung als Event fungiert
- 1 zu n mit event trigger
```
syncRule syncCompleteNameFromSimplePerson {
from
c : SimplePersons!SimplePerson (completeName)
do
syncNameFunction (c.firstName : String, c.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
}
syncRule syncFirstNameFromMember {
from
a : Families!Member (firstName) //variablen Änderung auf die diese Regel reagieren soll
do
syncNameFunction (a.firstName : String, a.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
}
syncRule syncLastNameFromFamily {
from
a : Families!Family (lastName) //variablen Änderung auf die diese Regel reagieren soll
do
syncNameFunction (a.firstName : String, a.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
}
syncRule syncFullNameFromPerson {
from
b : Persons!Person (fullName)
do
syncNameFunction (b.firstName : String, b.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
}
```
- diese Regel kümmert sich um die Durchführung der Synchronisation und wird nur von denen davor aufgerufen wenn eine Änderung wo eintritt
```
syncRule syncNameFunction ( firstName : String, lastName : String ) {
in
a : Families!Member (
a.firstName <- firstName
),
d : Families!Family (
d.lastName <- lastName
),
b : Persons!Person (
b.fullName <- firstName + ' ' + lastName
),
c : SimplePersons!SimplePerson (
c.completeName <- firstName + ' ' + lastName
)
}
```
### Idee 3
- Kürzeste aller Regeln und beschreibt die Synchronisation des Namens aller Objekte perfekt
- Mit dem richtigen Code Generator wird auch kein unötiger Aufruf in dem Model durchgeführt welches die Synchronisation auslöst
- Synchronisationsregeln anderer Attribute müssen extra definiert werden
```
syncRule NamesOfFamilyAndMemberAndPersonAndSimplePerson {
sync
a : Families!Member
b : Persons!Person
c : SimplePersons!SimplePerson
d : Families!Family (a.family==d)
with
a.firstName + ' ' + d.lastName == b.fullName == c.completeName
//falls completeName = d.lastName + ',' + a.firstName wäre es möglich die Regel so zu schreiben
a.firstName + ' ' + d.lastName == b.fullName
d.lastName + ',' + a.firstName == c.completeName
//oder mittels hilfsfunktionen in b und c könnte man auch sowas schreiben
a.firstName + ' ' + d.lastName == b.firstName + ' ' + b.lastName == c.lastName + ',' + c.firstName
}
```
## Create Rules
- 2 Ideen wie man Erstellungsregeln aufbauen kann, zum einen wie in ATL oder so hier
- In beiden Arten muss man unterscheiden in männlich und weiblich da dies die meisten Probleme verursacht
### Meine Idee für andere Art von Erstellungsregeln
```
createRule MemberAndPersonAndSimplePerson {
of
s : Families!Member (s.isFemale())
s1 : Persons!Female
s2 : SimplePersons!SimplePerson (not s2.male)
with (brauche ich hier gar nicht)
s.firstName + ' ' + s.lastName == s1.fullName == s2.completeName //s.lastName musst be a helper function
// Abbilden der Weiblichkeitsbeziehung nicht anders machbar
to
t1 : Families!Family (
lastName <- s1.lastName == s2.lastName
),
t2 : Families!Member (
firstName <- s1.firstName == s2.firstName,
familyDaughter <- t1
),
t3 : SimplePersons!SimplePerson (
completeName <- s.firstName + ' ' + s.lastName == s1.fullName,
male <- Boolean.FALSE
),
t4 : Persons!Female (
fullName <- s.firstName + ' ' + s.lastName == s2.completeName
)
}
createRule MemberAndPersonAndSimplePerson {
of
s : Families!Member (not s.isFemale())
s1 : Persons!Male
s2 : SimplePersons!SimplePerson (s2.male)
with (brauche ich hier gar nicht)
s.firstName + ' ' + s.lastName == s1.fullName == s2.completeName //s.lastName musst be a helper function
// Abbilden der Weiblichkeitsbeziehung nicht anders machbar
to
t1 : Families!Family (
lastName <- s1.lastName == s2.lastName
),
t2 : Families!Member (
firstName <- s1.firstName == s2.firstName,
familySon <- t1
),
t3 : SimplePersons!SimplePerson (
completeName <- s.firstName + ' ' + s.lastName == s1.fullName,
male <- Boolean.TRUE
),
t4 : Persons!Male (
fullName <- s.firstName + ' ' + s.lastName == s2.completeName
)
}
```
### ATL Variante mit einem Input und mehreren Output Modellen
### Von Families aus
```
createRule Families2PersonAndSimplePersonFemale {
from
s : Families!Member (s.isFemale())
to
t1 : SimplePersons!SimplePerson (
completeName <- s.firstName + ' ' + s.lastName,
male <- Boolean.FALSE
),
t2 : Persons!Female (
fullName <- s.firstName + ' ' + s.lastName
)
}
createRule Families2PersonAndSimplePersonMale {
from
s : Families!Member (not s.isFemale())
to
t1 : SimplePersons!SimplePerson (
completeName <- s.firstName + ' ' + s.lastName,
male <- Boolean.TRUE
),
t2 : Persons!Male (
fullName <- s.firstName + ' ' + s.lastName
)
}
```
### Von Person aus
```
createRule Persons2FamiliesAndSimplePersonFemale {
from
s : Persons!Female
to
t1 : Families!Family (
lastName <- s.lastName
),
t2 : Families!Member (
firstName <- s.firstName,
familyDaughter <- t1
),
t3 : SimplePersons!SimplePerson (
completeName <- s.fullName, // s.firstName + ' ' + s.lastName,
male <- Boolean.FALSE
)
}
createRule Persons2FamiliesAndSimplePersonMale {
from
s : Persons!Male
to
t1 : Families!Family (
lastName <- s.lastName
),
t2 : Families!Member (
firstName <- s.firstName,
familySon <- t1
),
t3 : SimplePersons!SimplePerson (
completeName <- s.fullName, // s.firstName + ' ' + s.lastName,
male <- Boolean.TRUE
)
}
```
### Von SimplePerson aus
```
createRule SimplePersons2FamiliesAndPersonFemale {
from
s : SimplePersons!SimplePerson (not s.male)
to
t1 : Families!Family (
lastName <- s.lastName
),
t2 : Families!Member (
firstName <- s.firstName,
familyDaughter <- t1
),
t3 : Persons!Famale (
fullName <- s.completeName // s.firstName + ' ' + s.lastName
)
}
createRule SimplePersons2FamiliesAndPersonMale {
from
s : SimplePersons!SimplePerson (s.male)
to
t1 : Families!Family (
lastName <- s.lastName
),
t2 : Families!Member (
firstName <- s.firstName,
familySon <- t1
),
t4 : Persons!Male (
fullName <- s.completeName // s.firstName + ' ' + s.lastName
)
}
```
## Delete Rules
```
deleteRule MembersAndPersonsAndSimplePersons {
of
s1 : Families!Member
s2 : SimplePersons!SimplePerson
s3 : Persons!Person
without (Ich weiß nicht ob man das benötigt)
s3 : Persons!Person
}
```
- Regel für interne Relationen in Modellen
- Eigentlich uninteressant für die Sprache jedoch wäre es schon schön die irgendwie mit abzudecken
```
deleteRule FamiliesAndMembers {
from
s1 : Families!Member (s1.onlyFamilyMember())
s2 : Families!Family
}
```
# HYBRID ANSATZ
- Verwenden von kompletten Regeln (1) und getrennten Regeln (2)
- Vorteil:
- kurze Regelschreibweisen möglich
- feingranuales betrachten von Elementtypen möglich
- Nachteil:
- kompliziertere Regelsprache durch das Abdecken aller Fälle
- kann zu unübersichtlichkeiten innerhalb der Regeln kommen
- oberen 2 Ansätze verbinden
- erst möglich falls beide Ansätze komplett ausgearbeitet sind
# HELPER CONTEXT RULES (from ATL)
- Können wir in unserem Ansatz einfach wieder verwenden
- Neues Compartment für Helper Regeln mit einer Menge an Rollen für verschiedene Elemente aus den unterschiedlichen Modellen
- Beispiele eine Rolle für Families!Member welche die Funktionen implementiert:
- helperFamily : Families!Family
- helperFamilyName : String
- helperIsFemale : Boolean
```
helper context Families!Member def : family : Families!Family =
if not self.familyFather.oclIsUndefined () then
self.familyFather
else
if not self.familyMother.oclIsUndefined () then
self.familyMother
else
if not self.familySon.oclIsUndefined () then
self.familySon
else
self.familyDaughter
endif
endif
endif;
helper context Families!Member def : familyName : String =
if not self.familyFather.oclIsUndefined () then
self.familyFather.lastName
else
if not self.familyMother.oclIsUndefined () then
self.familyMother.lastName
else
if not self.familySon.oclIsUndefined () then
self.familySon.lastName
else
self.familyDaughter.lastName
endif
endif
endif;
helper context Families!Member def : isFemale () : Boolean =
if not self.familyMother.oclIsUndefined () then
true
else
if not self.familyDaughter.oclIsUndefined ( ) then
true
else
false
endif
endif;
```
### Helper Regeln um an die firstName und lastName Elemente aus Person und SimplePerson zu kommen
```
helper context SimplePersons!SimplePerson def : firstName : String =
self.completeName.split(' ').first;
helper context SimplePersons!SimplePerson def : lastName : String =
self.completeName.split(' ').last;
helper context Persons!Person def : firstName : String =
self.fullName.split(' ').first;
helper context Persons!Person def : lastName : String =
self.fullName.split(' ').last;
```