MetaCase Homepage
Forum Home Forum Home > > MetaEdit+
  New Posts New Posts RSS Feed - How to compare elements at ends of a relationship?
  FAQ FAQ  Forum Search   Events   Register Register  Login Login

How to compare elements at ends of a relationship?

 Post Reply Post Reply
Author
Message
alev View Drop Down
Contributor
Contributor
Avatar

Joined: 08.Oct.2010
Location: Arnhem, NL
Points: 19
Post Options Post Options   Thanks (0) Thanks(0)   Quote alev Quote  Post ReplyReply Direct Link To This Post 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!
Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post 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
Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post 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
Back to Top
alev View Drop Down
Contributor
Contributor
Avatar

Joined: 08.Oct.2010
Location: Arnhem, NL
Points: 19
Post Options Post Options   Thanks (0) Thanks(0)   Quote alev Quote  Post ReplyReply Direct Link To This Post 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!
Back to Top
alev View Drop Down
Contributor
Contributor
Avatar

Joined: 08.Oct.2010
Location: Arnhem, NL
Points: 19
Post Options Post Options   Thanks (0) Thanks(0)   Quote alev Quote  Post ReplyReply Direct Link To This Post 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
Back to Top
stevek View Drop Down
MetaCase
MetaCase
Avatar

Joined: 11.Mar.2008
Points: 643
Post Options Post Options   Thanks (0) Thanks(0)   Quote stevek Quote  Post ReplyReply Direct Link To This Post 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).

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Forum Software by Web Wiz Forums® version 12.05
Copyright ©2001-2022 Web Wiz Ltd.

This page was generated in 0.039 seconds.