Hi,
currently opposites are described as
opposite and opposite+derived. This can be one->one, one->many, many->one and many->many. We can easily generate code which handles all those different cases.
Secondly, when we are writing out instances of fm3-described classes; we know when attributes have an opposite. There the derived is quite unimportant; since it is just a hint to the writer "which" of the 2 opposites it should write and which it should derive. However, since you can generate code which takes all different cases into account, writing it out (and reading it in) either way is possible. The opposite can be filled in from either of the available relationships. So which opposite you file out could be chosen randomly. Coming to my point: do attributes which have an opposite need a derived statement? Isn't it more logical that only real algorithmic "attributes" are derived? When choosing automatically you will only have to take care that if an opposite is its own opposite (the opposite of the attribute "opposite" in fm3.Property is like this; that's probably the only case :)), that it always gets written.
#((( #This fact would again strengthen my case that the opposite of an opposite should not necessarily be #declared as an opposite in the MSE file. Nor should the type be in either of them. If we find (prop (id: 2) #(opposite (idref: 1))), then we should automatically do (objectAtId: 1).setOpposite(objectAtId: 2), #which sets the owner of (objectAtId: 2) as it's type, sets the type of the (objectAtId: 2) as the owner of #(objectAtId: 1); and then sets (objectAtId: 2) as the opposite of (objectAtId: 1) # #---->> if you use an opposite-declaration for an attribute; you have 1 statement instead of 5 for which 4 are #redundant ----> less redundancy => better performance #)))
any ideas / comments? Does this seem right / clean?
cheers, Toon
On 7 Dec 2007, at 15:51 , Toon Verwaest wrote:
currently opposites are described as opposite and opposite+derived. This can be one->one, one->many, many->one and many->many. We can easily generate code which handles all those different cases. Secondly, when we are writing out instances of fm3-described classes; we know when attributes have an opposite. There the derived is quite unimportant; since it is just a hint to the writer "which" of the 2 opposites it should write and which it should derive. However, since you can generate code which takes all different cases into account, writing it out (and reading it in) either way is possible. The opposite can be filled in from either of the available relationships. So which opposite you file out could be chosen randomly. Coming to my point: do attributes which have an opposite need a derived statement? Isn't it more logical that only real algorithmic "attributes" are derived? When choosing automatically you will only have to take care that if an opposite is its own opposite (the opposite of the attribute "opposite" in fm3.Property is like this; that's probably the only case :)), that it always gets written.
You are right, the derived opposites are a mere hint. Some points why this might nevertheless be a good idea to keep them, we are not the only client of mse
- generated code is not the only use-case - there is legacy code that does not update opposites automatically - some people use hardcoded mse exporters - some people use hardcoded mse importers
#(((#This fact would again strengthen my case that the opposite of an opposite should not necessarily be #declared as an opposite in the MSE file. Nor should the type be in either of them. If we find (prop (id: 2) #(opposite (idref: 1))), then we should automatically do (objectAtId: 1).setOpposite(objectAtId: 2), #which sets the owner of (objectAtId: 2) as it's type, sets the type of the (objectAtId: 2) as the owner of #(objectAtId: 1); and then sets (objectAtId: 2) as the opposite of (objectAtId: 1) # #---->> if you use an opposite-declaration for an attribute; you have 1 statement instead of 5 for which 4 are #redundant ----> less redundancy => better performance #)))
Do you have a reference implementation?
any ideas / comments? Does this seem right / clean? cheers, Toon _______________________________________________ Moose-dev mailing list Moose-dev@iam.unibe.ch https://www.iam.unibe.ch/mailman/listinfo/moose-dev
Adrian Kuhn wrote:
- generated code is not the only use-case
- there is legacy code that does not update opposites automatically
- some people use hardcoded mse exporters
- some people use hardcoded mse importers
right .. backwards compatibility.... the horror of microsoft nightmares all over again
#(((#This fact would again strengthen my case that the opposite of an opposite should not necessarily be #declared as an opposite in the MSE file. Nor should the type be in either of them. If we find (prop (id: 2) #(opposite (idref: 1))), then we should automatically do (objectAtId: 1).setOpposite(objectAtId: 2), #which sets the owner of (objectAtId: 2) as it's type, sets the type of the (objectAtId: 2) as the owner of #(objectAtId: 1); and then sets (objectAtId: 2) as the opposite of (objectAtId: 1) # #---->> if you use an opposite-declaration for an attribute; you have 1 statement instead of 5 for which 4 are #redundant ----> less redundancy => better performance #)))
Do you have a reference implementation?
Not yet, shouldn't be too difficult though...
What I -did- implement today in my python version is "onemany.py", which is a implementation of a One class and a Many class which are polymorphic "Opposite" descendants. Which both have a pointer to their owner instance. This allows me to use them as instance variables of (their owner instances), and instead of setting these instance variables and updating the other side of a (one->one, one->many or many->many relationship), these Opposite-descendants get a new Opposite added. This implements the 3 scenarios by using just 2 (polymorphic) classes.
Example of a use (this is generated code, I indicated the lines to read with "%"):
class LocalVariable(StructuralEntity.StructuralEntity): def __init__(self): StructuralEntity.StructuralEntity.__init__(self) % self.gen_parentBehaviouralEntity = onemany.One(self)
def getParentBehaviouralEntity(self): # .value() returns the owner of the opposite Opposite descendant % return self.gen_parentBehaviouralEntity.value()
def setParentBehaviouralEntity(self, gen_parentBehaviouralEntity): import BehaviouralEntity assert(isinstance(gen_parentBehaviouralEntity, BehaviouralEntity.BehaviouralEntity)) % self.gen_parentBehaviouralEntity.add(gen_parentBehaviouralEntity.gen_localVariables)
class BehaviouralEntity(ContainerEntity.ContainerEntity): def __init__(self): ContainerEntity.ContainerEntity.__init__(self) self.gen_outgoingInvocations = onemany.Many(self) % self.gen_localVariables = onemany.Many(self) self.gen_parameters = onemany.Many(self) self.gen_outgoingAccesses = onemany.Many(self) self.gen_signature = None
% def getLocalVariables(self): # values returns a [] of owners of the opposite Opposite descendants % return self.gen_localVariables.values()
def setLocalVariables(self, gen_localVariables): import LocalVariable assert(isinstance(gen_localVariables, list)) for i in gen_localVariables: assert(isinstance(i, LocalVariable.LocalVariable)) # On the setting of many-side you have to clear manually since adding does not remove for Many % self.gen_localVariables.clear() % for i in gen_localVariables: % self.gen_localVariables.add(i.gen_parentBehaviouralEntity)
((in the code I prepend gen_ to all instance variable names to avoid conflicts with existing keywords))
if you want to run it yourself, do "python fm3codegenerator.py FAMIX30.fm3.mse" (FAMIX30.fm3.mse not supplied in that svn dir)
cheers, Toon
Toon Verwaest wrote:
Adrian Kuhn wrote:
- generated code is not the only use-case
Oh and right; what -IS- the other use-case which is not covered by what I explained?
- there is legacy code that does not update opposites automatically
- some people use hardcoded mse exporters
- some people use hardcoded mse importers
right .. backwards compatibility.... the horror of microsoft nightmares all over again
#(((#This fact would again strengthen my case that the opposite of an opposite should not necessarily be #declared as an opposite in the MSE file. Nor should the type be in either of them. If we find (prop (id: 2) #(opposite (idref: 1))), then we should automatically do (objectAtId: 1).setOpposite(objectAtId: 2), #which sets the owner of (objectAtId: 2) as it's type, sets the type of the (objectAtId: 2) as the owner of #(objectAtId: 1); and then sets (objectAtId: 2) as the opposite of (objectAtId: 1) # #---->> if you use an opposite-declaration for an attribute; you have 1 statement instead of 5 for which 4 are #redundant ----> less redundancy => better performance #)))
Do you have a reference implementation?
Not yet, shouldn't be too difficult though...
I just had a look at this, and it actually already automatically works, since opposites are defined as One instances of my implementation of One to One relations; since they have an opposite. When you write one of the opposites; the other one is automatically set. (I don't set the types automatically yet; but that should only be two lines of code)
Writing this out to an MSE file with only one opposite also doesn't work yet; since my derived-flag (which is chosen automatically; the first property with an opposite that comes will be written; the other site is automatically the derived one) of an opposite attribute is stored in the opposite attribute itself; and since "opposite"(the opposite attribute of the FM3.Property) is its own opposite attribute; this would stop the writer from writing anything. But since this is a one to one; for this case I could instead of saving it in the opposite attribute; just keep a list of instances which are derived; instead of descriptions which are derived.
I hope that the text with the opposites is not -too- confusing :)
Toon
On 10 Dec 2007, at 11:29 , Toon Verwaest wrote:
I just had a look at this, and it actually already automatically works, since opposites are defined as One instances of my implementation of One to One relations; since they have an opposite. When you write one of the opposites; the other one is automatically set. (I don't set the types automatically yet; but that should only be two lines of code)
Cool!
Writing this out to an MSE file with only one opposite also doesn't work [...snip...]
I dont know if writing is necessary, as I understood your usecase is import of handwritten metamoels, right?
AA
Adrian Kuhn wrote:
On 10 Dec 2007, at 11:29 , Toon Verwaest wrote:
I just had a look at this, and it actually already automatically works, since opposites are defined as One instances of my implementation of One to One relations; since they have an opposite. When you write one of the opposites; the other one is automatically set. (I don't set the types automatically yet; but that should only be two lines of code)
Cool!
Now the types also work. For this I just had to change the accessor (getType) of property to:
if self.hasOpposite(): return self.getOpposite().getOwningClass() else: return self.type
Code generation uses these accessors instead of direct access anyway; so it nicely generates correct type-asserts.
Writing this out to an MSE file with only one opposite also doesn't work [...snip...]
I dont know if writing is necessary, as I understood your usecase is import of handwritten metamoels, right?
Right. However, I think that we should also try to reduce filesizes where possible anyhow. This is quite straightforward and applies to all situations so... why not?
So for those not getting it; I basically implemented the reduction from 5 attribute declarations of two opposite fm3.Property in mse-files to one attribute in one of these opposite properties. Opposite+type+derived and opposite+type to just one time opposite.
cheers