![]() |
How to compare elements at ends of a relationship? |
Post Reply
|
| Author | |
alev
Contributor
Joined: 08.Oct.2010 Location: Arnhem, NL Points: 19 |
Post Options
Thanks(0)
Quote Reply
Topic: How to compare elements at ends of a relationship?Posted: 08.Oct.2010 at 12:21 |
|
Hi,
I would like to compare (in MERL) contents of two properties of the same type. The type of the properties is collection of Graphs. Each property belongs to a different object. Objects are connected by a relationship. In other words: collectionA :property.object1~src_role>relationship~tgt_role.object2:property collectionB Starting point is the relationship. Navigating to a collection at either end is not a problem. I am having a trouble accessing a collection at the other object (e.g. object2) while being in object1. What is the best way to tackle this? Thanks! |
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 08.Oct.2010 at 13:27 |
|
Let's look at the simplest case first: you want the collection to look the same at both ends. Here's an example for two UML Classes, with a generator in the symbol for the relationship between them, to show whether they are the same. Test by deep copying the same class and connecting the copies. do ~Whole.Class [UML]
{ $wholeAttrs = :Attributes } do ~Part.Class [UML] { if :Attributes = $wholeAttrs then 'ok' else 'wrong' endif } If you need more in-depth comparison, you can store the details of the first collection in separate variables, e.g. one per element. I'll store id's here, since I've deep-copied the collection; you probably want to store oid's, if you want to check if it is exactly the same element, not just one with the same name.
Note how we make associative variables: variable ... write ... close. Anything in the first block of commands goes to make up the name of the variable, e.g. here wholeAttr0. You can think of that as wholeAttr[0] if you like - arrays are just a special case of associative variables, and a very limited one at that.
to '%null' newline '* $' endto
$ix1='0' do ~Whole.Class [UML]:Attributes { variable 'wholeAttr' $ix1++ write id close } $ix2='0' do ~Part.Class [UML]:Attributes { variable 'oldAttr' write variable 'wholeAttr' $ix2++ read close if id <> $oldAttr then $errors++%null endif } if $ix1 <> $ix2 then $errors++%null endif if $errors then 'wrong' else 'ok' endif I guess that what you were trying to do was iterate over one collection, and in the middle of that iterate over the other. That's slower, because it's O(N^2) - for each element on the left, you have to navigate across to the object on the right, then iterate through its elements to find the right one. You can do it though:
to '%null' newline '* $' endto
$ix1='0' do ~Whole.Class [UML]:Attributes { $ix1++%null $ix2='0' do ~Part;1.Class [UML]:Attributes { if $++ix2 = $ix1 and id;1 <> id then $errors++%null endif } } if $ix1 <> $ix2 then $errors++%null endif if $errors then 'wrong' else 'ok' endif Note the ;1 which says to evaluate the preceding command in the context one level higher in the stack, i.e. one {} block out. Otherwise if we tried to navigate to the ~Part role from the first Attribute, MERL would correctly say that there are no roles attached to the Attribute. Instead we ask the question one level further out, where we are still in the relationship.
All these comparisons require both collections to be in the same order. If you want to compare as sets, just sort the do loops with "orderby". Edited by stevek - 08.Oct.2010 at 13:27 |
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 08.Oct.2010 at 13:38 |
|
Actually, the first solution can be made even shorter: if ~Whole.():Attributes = ~Part.():Attributes; then 'ok' else 'wrong' endif
|
|
![]() |
|
alev
Contributor
Joined: 08.Oct.2010 Location: Arnhem, NL Points: 19 |
Post Options
Thanks(0)
Quote Reply
Posted: 08.Oct.2010 at 13:50 |
|
Stevek, thank you for a prompt and detailed answer. You are right that the third case is what I was trying to do. I will follow you advice and let you know how it works!
|
|
![]() |
|
alev
Contributor
Joined: 08.Oct.2010 Location: Arnhem, NL Points: 19 |
Post Options
Thanks(0)
Quote Reply
Posted: 08.Oct.2010 at 18:55 |
|
Steven,
I adapted your 3rd case as follows: to '%null' newline '* $' endto $matches = '0' $ix1='0' do ~inflow.pFunction:outputs { $ix1++%null $ix2='0' do ~outflow;1.pFunction:inputs { if oid;1 = oid then $matches++%null endif } } $matches [edited to show indents lost when pasting. -Steve] The problem is that only the 1st 'do' block iterates over collection and the 2nd block does not. I thought may be it had something to do with values of the attributes, so I switched '~inflow.pFunction:outputs' with '~outflow;1.pFunction:inputs' to test this. Again, only the 1st loop iterated. Any ideas? Thanks. Edited by stevek - 08.Oct.2010 at 19:48 |
|
![]() |
|
stevek
MetaCase
Joined: 11.Mar.2008 Points: 643 |
Post Options
Thanks(0)
Quote Reply
Posted: 08.Oct.2010 at 20:04 |
|
The code looks right, apart from having unused $ix1 and $ix2 - which won't stop it working. Check your typing of the class names. Check you're starting from the relationship between ~inflow and ~outflow, not e.g. an object which has ~inflow but no ~outflow. Use the debugger and a breakpoint or Step Into to see why the inner loop isn't executed. You can get more information during debugging if you break the inner loop's navigation into several nested do loops, one for each part (remember to increment the level number in oid;1 each time you add a loop). |
|
![]() |
|
Post Reply
|
|
| Tweet |
| Forum Jump | Forum Permissions ![]() You cannot post new topics in this forum You cannot reply to topics in this forum You cannot delete your posts in this forum You cannot edit your posts in this forum You cannot create polls in this forum You cannot vote in polls in this forum |