| | 86 | # represent a one to many relationship between the |
| | 87 | # "Property" and "Class" MetaClasses. The association is |
| | 88 | # called .properties on the Class end, and .class on the |
| | 89 | # property end. |
| | 90 | |
| | 91 | my $Property_mc = Perl::MetaClass->new("Property"); |
| | 92 | my $Class_mc = Perl::MetaClass->new("Class"); |
| | 93 | |
| | 94 | $Class_mc->clsAssocs |
| | 95 | (properties => Perl::MetaAssoc->new |
| | 96 | ( |
| | 97 | assocOrdered => false, |
| | 98 | assocRange => [0, inf], |
| | 99 | assocCompanion => "class", |
| | 100 | assocIsComposite => true, |
| | 101 | assocPair => Perl::MetaAssoc->new |
| | 102 | ( assocRange => [1, 1], |
| | 103 | assocClass => $Property_mc ) |
| | 104 | ) |
| | 105 | ); |
| | 106 | |
| | 108 | |
| | 109 | A Perl::MetaAssoc represents a fairly abstract concept. Firstly, it |
| | 110 | is a class of the B<meta-model>, which is not C<Class.meta()> objects |
| | 111 | at all. That distinction is explained at L<Perl::MetaClass>. |
| | 112 | |
| | 113 | This class is used to describe I<relationships> between two classes in |
| | 114 | the Class model. For instance, a Class can have any number of defined |
| | 115 | methods, and each method can only belong to one class. These two |
| | 116 | comments are frequently viewed as being seperate relationships, but in |
| | 117 | fact they are simply different ways of looking at the same |
| | 118 | relationship; that a method belongs to exactly one class (or package, |
| | 119 | or whatever). |
| | 120 | |
| | 121 | Each side of the relationship is identical to the other; so, in this |
| | 122 | metamodel, relationships are represented with I<two> objects - one for |
| | 123 | each side. |
| | 124 | |
| | 125 | There is a lot of implicit 'magic' assumed to be happening in the |
| | 126 | example. This magic stems from rules such as the following; |
| | 127 | |
| | 128 | ∀ MetaClass A, MetaAssoc C : A.clsAssoc ∋ C ↔ C.assocClass = A |
| | 129 | |
| | 130 | This is read as "For every MetaClass A and MetaAssoc C, such that |
| | 131 | A.clsAssoc contains C, it is automatically implied that C.assocClass |
| | 132 | is A". |
| | 133 | |
| | 134 | We could have written this explicitly: |
| | 135 | |
| | 136 | my $properties_class_ma = Perl::MetaAssoc->new(); |
| | 137 | $Class_mc->clsAssocs("properties" => $properties_class_ma); |
| | 138 | $properties_class_ma->assocClass($Class_mc); |
| | 139 | |
| | 140 | However, this would be needless duplication of expressing the |
| | 141 | relationship; we want this all to happen automatically. |
| | 142 | |
| | 143 | This rule is almost identical: |
| | 144 | |
| | 145 | ∀ MetaAssoc C₁, C₂ : C₁.assocPair = C₂ ↔ C₂.assocPair = C₁ |
| | 146 | |
| | 147 | Just by stating that the C<assocPair> for one of the C<MetaAssoc> |
| | 148 | objects is the other, we don't need to specify the reverse relation. |
| | 149 | |
| | 150 | Similarly, as we have stated; |
| | 151 | |
| | 152 | ∀ MetaAssoc C₁, C₂, MetaClass M₁, M₂ |
| | 153 | : C₁.catPair = C₂ ∧ C₁.assocCompanion |
| | 154 | ∧ C₁.catClass = M₁ ∧ C₂.catClass = M₂ |
| | 155 | → ( ∃ M₁.clsAssocs{C₂.catCompanion} |
| | 156 | ∧ ∃ M₂.clsAssocs{C₁.catCompanion} |
| | 157 | ∧ M₁.clsAssocs{C₂.catCompanion}[1] = C₁ |
| | 158 | ∧ M₂.clsAssocs{C₁.catCompanion}[1] = C₂ |
| | 159 | ∧ M₁.clsAssocs{C₂.catCompanion}[0] = M₂.clsAssocs{C₁.catCompanion}[0] |
| | 160 | ) |
| | 161 | |
| | 162 | Then simply by specifying that the C<properties> MetaAssoc object's |
| | 163 | companion is called "class", this will mean that its pair MetaAssoc |
| | 164 | object's name within the "Property" clsAssocs collection is "class". |
| | 165 | It also implies that the pair MetaAssoc will have a C<companion> |
| | 166 | property of "properties". |
| | 167 | |
| | 168 | Finally, it is implied that the other side of the association cannot |
| | 169 | be composite; |
| | 170 | |
| | 171 | ∀ MetaAssoc C₁, C₂ : C₁.assocPair = C₂ ∧ C₁.assocIsComposite |
| | 172 | → ¬(C₂.catIsComposite) |