Home » Modeling » VIATRA » Please criticise my transformation
Please criticise my transformation [message #645339] |
Thu, 16 December 2010 16:57 |
Tassilo Horn Messages: 93 Registered: July 2009 |
Member |
|
|
Hi all,
I've finished my first transformation. It's a slight extension of the
ATL tutorial's Families2Persons transformation. Basically, on the
source side there are Families connected to Members with different
relations (father, mother, sons, daughters), and on the target side,
there are Males and Females with an abstract supertype Person, and
a Male relates to his wife, and parents to their children.
My transformation seems to work properly (at least, I get what I
expect), but since it is my first self-made VIATRA2 transformation, I'd
be very happy for comments and improvement suggestions!
Especially, the transformation seem overly verbose to me because of
pretty much code duplication (like in the childParentMapping pattern).
The complete eclipse project containing the model space and the
transformation can be downloaded from
http://www.uni-koblenz.de/~horn/Families2PersonsVIATRA2.tar. gz
Ok, so this is my code:
--8<---------------cut here---------------start------------->8---
namespace familymodel2genealogy;
import Families.metamodel;
import Persons.metamodel;
machine FamilyModel2Genealogy {
// ENTRY POINT
rule main() = call transform();
// PATTERNS
pattern memberMapping(M, P) = {
Member(M);
Person(P);
Member.member2person(Traces, M, P);
}
pattern maleMemberMapping(M, P) = {
Male(P);
find memberMapping(M, P);
}
pattern femaleMemberMapping(M, P) = {
Female(P);
find memberMapping(M, P);
}
pattern familyModelMapping(FM, G) = {
FamilyModel(FM);
Genealogy(G);
FamilyModel.familymodel2genealogy(Traces, FM, G);
}
pattern isFemale(M) = {
Member(M);
Family(SomeFamily);
Family.mother(X, SomeFamily, M);
} or {
Member(M);
Family(SomeFamily);
Family.daughters(X, SomeFamily, M);
}
pattern familyMapping(F, A) = {
Family(F);
Address(A);
Family.family2address(X, F, A);
}
pattern childParentMapping(C, PC, PP) = {
Member(C);
find memberMapping(C, PC);
Family(Fam);
Family.sons(S, Fam, C);
Member(P);
Family.father(X, Fam, P);
find memberMapping(P, PP);
} or {
Member(C);
find memberMapping(C, PC);
Family(Fam);
Family.daughters(S, Fam, C);
Member(P);
Family.father(X, Fam, P);
find memberMapping(P, PP);
} or {
Member(C);
find memberMapping(C, PC);
Family(Fam);
Family.daughters(S, Fam, C);
Member(P);
Family.mother(X, Fam, P);
find memberMapping(P, PP);
} or {
Member(C);
find memberMapping(C, PC);
Family(Fam);
Family.sons(S, Fam, C);
Member(P);
Family.mother(X, Fam, P);
find memberMapping(P, PP);
}
pattern mappedChild(PC, PP) = {
Person(PC);
Person(PP);
Person.children(X, PP, PC);
}
pattern mainFamily(M, F) = {
Member(M);
Family(F);
Family.father(X, F, M);
} or {
Member(M);
Family(F);
Family.mother(X, F, M);
} or {
Member(M);
Family(F);
Family.sons(X, F, M);
} or {
Member(M);
Family(F);
Family.daughters(X, F, M);
}
// GT RULES
gtrule transformFamilyModel(out FM, out G) = {
precondition pattern unmappedFamilyModel(FM) = {
FamilyModel(FM);
neg find familyModelMapping(FM, NoGenealogy);
}
postcondition
find familyModelMapping(FM, G)
action {
move(G, Persons.model);
rename(G, name(FM) + "Genealogy");
call members2Persons(FM, G);
call families2Addresses(FM, G);
call createRelations(FM);
}
}
gtrule transformFamily(out F, in G) = {
precondition pattern unmappedFamily(F, S, T, G) = {
Family(F);
Genealogy(G);
neg find familyMapping(F, NoAddress);
Family.street(S) in F;
Family.town(T) in F;
}
postcondition pattern mappedFamily(F, A, G) = {
find familyMapping(F, A);
Genealogy(G);
}
action {
move(A, Persons.model);
rename(A, name(F) + "Address");
let Street = undef, Town = undef in seq {
new(Address.street(Street) in A);
new(Address.town(Town) in A);
setValue(Street, value(S));
setValue(Town, value(T));
}
}
}
gtrule transformMaleMember(out M, in G) = {
precondition pattern unmappedMember(M, FN, LN, G) = {
Member(M);
Family(F);
Member.firstName(FN) in M;
find mainFamily(M, F);
Family.lastName(LN) in F;
Genealogy(G);
neg find isFemale(M);
neg find memberMapping(M, NoPerson);
}
postcondition pattern mappedMember(M, P, G) = {
find maleMemberMapping(M, P);
Person(P);
Genealogy(G);
Genealogy.persons(X, G, P);
}
action {
move(P, Persons.model);
rename(P, name(M));
let FullName = undef in seq {
new(Person.fullName(FullName) in P);
setValue(FullName, value(FN) + " " + value(LN));
}
}
}
gtrule transformFemaleMember(out M, in G) = {
precondition pattern unmappedMember(M, FN, LN, G) = {
Member(M);
Family(F);
Member.firstName(FN) in M;
find mainFamily(M, F);
Family.lastName(LN) in F;
Genealogy(G);
find isFemale(M);
neg find memberMapping(M, NoPerson);
}
postcondition pattern mappedMember(M, P, G) = {
find femaleMemberMapping(M, P);
Person(P);
Genealogy(G);
Genealogy.persons(X, G, P);
}
action {
move(P, Persons.model);
rename(P, name(M));
let FullName = undef in seq {
new(Person.fullName(FullName) in P);
setValue(FullName, value(FN) + " " + value(LN));
}
}
}
gtrule connectSpouse(out H) = {
precondition pattern husband(H, W, PH, PW) = {
Member(H);
Member(W);
Male(PH);
Female(PW);
find maleMemberMapping(H, PH);
find femaleMemberMapping(W, PW);
neg find isFemale(H);
find isFemale(W);
Family(Family);
Family.father(X, Family, H);
Family.mother(X2, Family, W);
}
postcondition pattern spouse(PH, PW) = {
Male(PH);
Female(PW);
Male.wife(S, PH, PW);
}
}
gtrule connectMemberToAddress(out M) = {
precondition pattern familyMember(M, P, A) = {
Member(M);
Person(P);
find memberMapping(M, P);
Address(A);
Family(F);
find mainFamily(M, F);
find familyMapping(F, A);
}
postcondition pattern livesAt(P, A) = {
Person(P);
Address(A);
Person.address(X, P, A);
}
}
gtrule connectParents(out C) = {
precondition pattern unconnectedChild(C, PC, PP) = {
Member(C);
Person(PC);
Person(CC);
find childParentMapping(C, PC, PP);
neg find mappedChild(PC, PP);
}
postcondition pattern connectedChild(C, PC, PP) = {
Member(C);
Person(PC);
Person(PP);
Person.children(HC, PP, PC);
}
}
// ASM RULES
rule transform() = seq {
let G = undef in
forall FM with apply transformFamilyModel(FM, G)
do println("Transformed " + fqn(FM) + " to " + fqn(G));
println("--- Transformation terminated. ");
}
rule members2Persons(in FM, in G) = seq {
forall MMember in FM with apply transformMaleMember(MMember, G)
do println("Transformed " + fqn(MMember));
forall FMember in FM with apply transformFemaleMember(FMember, G)
do println("Transformed " + fqn(FMember));
}
rule families2Addresses(in FM, in G) = seq {
forall Family in FM with apply transformFamily(Family, G)
do println("Transformed " + fqn(Family));
}
rule createRelations(in FM) = seq {
forall Member in FM with apply connectSpouse(Member)
do println("Connected spouse of " + fqn(Member));
forall Member in FM with apply connectMemberToAddress(Member)
do println("Connected Address of " + fqn(Member));
iterate call connectChildrenToParents(FM);
}
rule connectChildrenToParents(in FM) = seq {
choose Child in FM with apply connectParents(Child)
do println("Connected parents of " + fqn(Child));
}
}
--8<---------------cut here---------------end--------------->8---
Thank a lot for any suggestions!
Bye,
Tassilo
--
Dipl.-Inform. Tassilo Horn | Room: B015
University of Koblenz-Landau, Campus Koblenz | Phone: +49 (261) 287-2745
Institute for Software Technology | Mail: horn@uni-koblenz.de
Universitätsstr. 1, 56070 Koblenz, Germany |
|
|
|
Re: Please criticise my transformation [message #646006 is a reply to message #645339] |
Tue, 21 December 2010 14:45 |
Zoltan Ujhelyi Messages: 392 Registered: July 2015 |
Senior Member |
|
|
Hi,
sorry for a late response.
I looked at the transformation, it seems working, however, in case of GT Rules it seems that often postconditions and actions are used together.
I think, it would be easier to read if the transformation rules would be expressed either purely declaratively (pre- and postcondition form), or purely imperatively (precondition and action), as it is hard to understand at first, what does the transformation do.
About the verboseness of the language I understand your concern. We have some ideas how to make the language more concise, but it is hard - especially because we don't have the resources to port the existing transformations, so backwards compatibility is an issue.
On the other hand, if you have some idea how to make it, we are glad to discuss them.
Zoltán Ujhelyi
PS.: Do you allow us to list your transformation in the VIATRA wiki among the transformations as an example. It may be used as a comparison between ATL and VIATRA. Thank you. Zoltán
|
|
|
Re: Please criticise my transformation [message #646027 is a reply to message #646006] |
Tue, 21 December 2010 16:14 |
Tassilo Horn Messages: 93 Registered: July 2009 |
Member |
|
|
Zoltán Ujhelyi <ujhelyiz@mit.bme.hu> writes:
Hi Zoltán,
> sorry for a late response.
I have to thank you for your helpful replies, so there's nothing you
have to be sorry for. :-)
> I looked at the transformation, it seems working, however, in case of
> GT Rules it seems that often postconditions and actions are used
> together.
>
> I think, it would be easier to read if the transformation rules would
> be expressed either purely declaratively (pre- and postcondition
> form), or purely imperatively (precondition and action), as it is hard
> to understand at first, what does the transformation do.
Hm, I can replace some imperative code like "move(A, Persons.model)" in
an action by using "Address(A) in Persons.model" in the postcondition.
But as far as I can see, rename() and setValue() are only available in
the action part, right?
So would you prefer splitting any rule with both postcondition and
action into two separate rules with identical preconditions? One with
only a postcondition for creating elements, and a second one with only
an action to rename the element and set attribute values?
> About the verboseness of the language I understand your concern. We
> have some ideas how to make the language more concise, but it is hard
> - especially because we don't have the resources to port the existing
> transformations, so backwards compatibility is an issue.
>
> On the other hand, if you have some idea how to make it, we are glad
> to discuss them.
I have no idea of how to make it, but things that I'd pretty much like
to omit is including conditions in preconditions that are already
implied by pattern calls. Example:
pattern memberMapping(M, P) = {
Member(M);
Person(P);
Member.member2person(Traces, M, P);
}
gtrule connectPersonToAddress(out M) = {
precondition pattern familyMember(M, P, A) = {
Member(M); // redundant
Person(P); // redundant
find memberMapping(M, P); // implies the two above
Address(A);
Family(F);
find mainFamily(M, F);
find familyMapping(F, A);
}
// ...
}
The "find memberMapping(M, P)" already implies that M is a Member and P
is a Person, so having to specify that again seems redundant to me, at
least from a plain user's perspective.
> PS.: Do you allow us to list your transformation in the VIATRA wiki
> among the transformations as an example. It may be used as a
> comparison between ATL and VIATRA.
Sure, but please name me as the author including my (obfuscated) email
address, because I will use that transformation in the related work of
my dissertation, and I do not want to be accused of having copied &
pasted that example from the VIATRA2 wiki.
I've based it on the ATL tutorial transformation available at
http://wiki.eclipse.org/ATL/Tutorials_-_Create_a_simple_ATL_ transformation
but extended the metamodels in various ways to make it more interesting.
I've written that transformation in ATL, QVTo, QVTr, GrGen.NET, and now
I'm doing it in Tefkat. Others will follow.
If you want, I can send you all of them. Simply drop me a mail.
Bye,
Tassilo
--
Dipl.-Inform. Tassilo Horn | Room: B015
University of Koblenz-Landau, Campus Koblenz | Phone: +49 (261) 287-2745
Institute for Software Technology | Mail: horn@uni-koblenz.de
Universitätsstr. 1, 56070 Koblenz, Germany |
|
|
|
Re: Please criticise my transformation [message #646129 is a reply to message #646027] |
Wed, 22 December 2010 09:22 |
Zoltan Ujhelyi Messages: 392 Registered: July 2015 |
Senior Member |
|
|
Hi,
Quote: | Hm, I can replace some imperative code like "move(A, Persons.model)" in
an action by using "Address(A) in Persons.model" in the postcondition.
But as far as I can see, rename() and setValue() are only available in
the action part, right?
So would you prefer splitting any rule with both postcondition and
action into two separate rules with identical preconditions? One with
only a postcondition for creating elements, and a second one with only
an action to rename the element and set attribute values?
|
You are right, there is no real support for these elements as far as I know. So you need both postcondition and action to write these patterns. So consider my previous idea as invalid.
Quote: | The "find memberMapping(M, P)" already implies that M is a Member and P
is a Person, so having to specify that again seems redundant to me, at
least from a plain user's perspective.
|
You are right, this is redundant. Currently, it is possible to remove the line Person(P) in this case, and the transformation would run this way, but it results in a warning, as it is not possible to calculate the type information for the pattern locally. So in this case it is not needed for execution, only the parser marks that this might cause problems (in some corner cases).
Quote: | Sure, but please name me as the author including my (obfuscated) email address, because I will use that transformation in the related work of
my dissertation, and I do not want to be accused of having copied &
pasted that example from the VIATRA2 wiki.
|
That's natural - it was your work after all. Thanks for sharing it with us.
Zoltán Ujhelyi
|
|
|
Re: Please criticise my transformation [message #646147 is a reply to message #646129] |
Wed, 22 December 2010 11:13 |
Tassilo Horn Messages: 93 Registered: July 2009 |
Member |
|
|
Zoltán Ujhelyi <ujhelyiz@mit.bme.hu> writes:
Hi Zoltán,
> You are right, there is no real support for these elements as far as I
> know. So you need both postcondition and action to write these
> patterns. So consider my previous idea as invalid. :d
Ok, but I support your statement that in general it is preferrable to
stick with one concept only.
>> The "find memberMapping(M, P)" already implies that M is a Member and
>> P is a Person, so having to specify that again seems redundant to me,
>> at least from a plain user's perspective.
>
> You are right, this is redundant. Currently, it is possible to remove
> the line Person(P) in this case, and the transformation would run this
> way, but it results in a warning, as it is not possible to calculate
> the type information for the pattern locally. So in this case it is
> not needed for execution, only the parser marks that this might cause
> problems (in some corner cases).
Yes, I already tested that, but I'm a person who is totally unable to
accept any warnings in his code. :-)
> Quote:
>> Sure, but please name me as the author including my (obfuscated) email
>> address, because I will use that transformation in the related work of
>> my dissertation, and I do not want to be accused of having copied &
>> pasted that example from the VIATRA2 wiki.
>
> That's natural - it was your work after all. Thanks for sharing it with us.
And I'm happy to help the community.
Bye,
Tassilo
--
Dipl.-Inform. Tassilo Horn | Room: B015
University of Koblenz-Landau, Campus Koblenz | Phone: +49 (261) 287-2745
Institute for Software Technology | Mail: horn@uni-koblenz.de
Universitätsstr. 1, 56070 Koblenz, Germany |
|
|
|
Goto Forum:
Current Time: Sun Dec 08 15:53:10 GMT 2024
Powered by FUDForum. Page generated in 0.04457 seconds
|