polygene-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stanislav Muhametsin <stanislav.muhamet...@zest.mail.kapsi.fi>
Subject Re: [Discuss] Object lifecycles...
Date Thu, 03 Dec 2015 23:28:32 GMT
Hi Kent,

sorry for long wait - I was socializing with friends.

Now, to give some examples - I'll just paste some code from Qi4CS unit 
tests and add explanations.

1. [Initialize]
This is the attribute marking methods which should be invoked 
immediately after fragment constructor (whenever that may occur).
The fragment has this simple method:

       public class TestCompositeMixin : TestComposite
       {
          ...
          [Initialize]
          public void DoInitialize() // This can also be 'protected'. 
Furthermore, 'internal' is supported, but with some CLR-specific 
constraints.
          {
             this._initialized = true;
          }
       }

It just sets the fragment field, which is later checked by the test to 
see that this method has actually been called:

             var composite = this.NewPlainComposite<TestComposite>();
             Assert.IsTrue( composite.IsInitialized(), "The 
initialization method of composite mixin must've been invoked." );

2. [Prototype]
This is the attribute marking methods which should be invoked when 
composite prototype stage ends, and composite is actually instantiated.
I'm not quite sure how this works in Zest at the moment, but in Qi4CS, 
no new composite is created at that point - instead, the 
CompositeInstance switches its internal state from "prototype" to "not 
prototype".

       public class TestCompositeMixin
       {
          [Prototype]
          public void PrototypeInitializer( [This] TestState state, 
[Uses][TestConstraint] Int32 someParam )
          {
             Assert.IsNull( state.MyProperty );
             state.MyProperty = PROPERTY_VALUE;
             Assert.AreEqual( state.MyProperty, PROPERTY_VALUE );
             _prototypeMethodCalled = true;
          }
       }

As you can see, this is more complex method than previous one, and it 
uses also injection parameters.
Both [Initialize] and [Prototype] methods are run before state is 
checked - therefore at this point, state may contain e.g. null properties.

3. [Activate]
This attribute is specific only for service composites.
Methods marked with this attribute are run when service composite is 
activated.
Currently, it is more simple logic than in Zest: activation of service 
happens either when the application is activated (if it is marked as 
activatable with application at assembly stage), or when someone invokes 
some method of the service for the first time since application activation.

       public class ServiceComposite1Mixin : ServiceComposite1
       {
          ...
          [Activate]
          public void Activate()
          {
             Assert.IsFalse( _isActive1 );
             _isActive1 = true;
          }
       }

Unlike [Initialize] and [Prototype], methods marked with [Activate] are 
run *after* composite has been created, ensuring that at method 
run-time, all state-checks for composite have been passed successfully.

The code for the test is actually partly originating from Zest:

             this.AssertNotActive( _isActive1 );
             var reference = 
this.StructureServices.FindService<ServiceComposite1>();
             this.AssertNotActive( _isActive1 );

             this.AssertNotActive( reference.Active );

             var service = reference.GetService();
             this.AssertNotActive( _isActive1 );

             service.DummyMethod();
             this.AssertActive( _isActive1 );

             this.Application.Passivate();
             this.AssertNotActive( _isActive1 );

4. [Passivate]
This attribute works like [Activate], but instead methods marked with 
this attribute are invoked on service composite passivation, which 
currently can happen only when application is passivated.

So far, these 4 attributes are the only lifecycle attributes present in 
Qi4CS.
The Qi4CS doesn't have entities, so some lifecycle aspects are obviously 
missing.
But I hope this post shed some light on how the lifecycle is handled 
over in C#/CLR world. :)

So far, I have no complaints over this concept of attributes marking 
'special' methods.
I use them quite a lot in the applications where I work currently.

P.S. Service composites in Qi4CS can also have [Initialize] and 
[Prototype] methods, and they are called by same logic.

On 03/12/2015 17:48, Kent SĂžlvsten wrote:
> interesting....
>
> My previous P.O.V was that we should support the equivalent of
> [Prototype] .... for mixins .
>
> Do you have some example use-cases from Qi4CS explaining the usage of
> [Initialize], or lifecycle methods on other fragment types?
>
> /Kent
>
>
> Den 03-12-2015 kl. 15:17 skrev Stanislav Muhametsin:
>> On 3.12.2015 9:38, Niclas Hedhman wrote:
>>> Gang,
>>>
>>> 1. Should Initializable.initalize() be invoked on prototypeFor()?
>>>
>>> At the moment, when prototypeFor() (and prototype() I guess) is
>>> called on
>>> TransientBuilder (probably ValueBuilder as well), the mixin's
>>> initialize()
>>> will be called.
>>> That means that the Composite is not really available (predictably)
>>> to the
>>> Mixin at this point.
>> In Qi4CS, I have [Initialize] and [Prototype] attributes (@Initialize
>> and @Prototype annotations in Java).
>> Methods on fragments marked with these attributes will be invoked by
>> Qi4CS runtime in the following logic:
>> 1. Methods marked with [Initialize] will be invoked the first time
>> fragment is created (be it during prototype stage, or composite
>> creation), right after its constructor finishes executing.
>> 2. Methods marked with [Prototype] will be invoked when the
>> CompositeBuilder actually creates composite instance (prototype stage
>> ends), during its NewInstance() method.
>>
>> Naming is maybe not optimal, but I think you get the general idea.
>> The concept on not having interfaces and instead using attributes
>> (annotations) stems from rather old e-mail from you, Niclas.
>> I see you have revisited this idea later in this mail. :)
>>
>>> 2. Do we have a solid object lifecycle story at all??
>>>
>>> While writing this mail, I start to think that the object lifecycle
>>> model
>>> is severely flawed, and possibly not easily fixed here and there.
>>>
>>> I think we need to dig through the requirements from the ground up. I
>>> think
>>> that the Fragments and the Composite need to be separated.
>>>
>>> I also wonder if we can indeed utilize finalize(), to get pre/post
>>> semantics uniformly across all composite meta types... Does anyone
>>> have a
>>> very strong understanding of how finalize() works, and why it is said
>>> to be
>>> "bad" to use it in programs??
>> Java's 'finalize' and C#'s destructors are very tricky, because most
>> assumptions that are valid during normal program flow, are not valid
>> in finalizers/destructors.
>> For example, in C#, the destructors are always run from within
>> dedicated finalizer thread (I don't know if Java does that).
>> Additionally, the fields of object during finalization/destruction
>> might point to already finalized objects, which can and usually does
>> cause a lot of subtle bugs.
>>
>> Personally, I've taken the stance recommended by C# - only use
>> destructors if your object needs to free native resources when it is
>> no longer used.
>>
>>> What I would like to see is pairs of annotations with strong semantics,
>>> something like (maybe better names)
>>>
>>> @OnEntityCreation   // called on EntityBuilder.newInstance()
>>> @OnEntityDeletion   // called on UnitOfWork.remove()
>>>
>>> @OnCompositeConstruction  // called when in-memory instance created
>>> @OnCompositeDestruction    // called via finalize() or UnitOfWork
>>> teardown.
>>>
>>> @OnMixinCreation      // Called after Mixin constructor call.
>>> @OnMixinDestruction  // called via @OnCompositeDestruction
>>>
>>> I am not sure if we need to separate the prototype/prototypeFor creation
>>> from the instantiation of 'final' Mixin instance that goes into the
>>> Composite.
>>>
>>> And in the process "fix" the ServiceComposite story as well, i.e.
>>>
>>> @OnServiceActivation
>>> @OnServicePassivation
>>>
>>> And in the process get rid of the all the related interfaces;
>>> Initializable
>>> Lifecycle
>>> Activatable
>>> ServiceActivator
>>>
>>> and so on.
>>>
>>> Any thoughts?
>> I think annotations are excellent idea, and they have worked for me in
>> Qi4CS very well.
>> One thing you need to be careful of, is in which order you invoke
>> them: base-class-first or bottommost-class-first in class inheritance
>> hierarchy.
>> IIRC Qi4CS invokes the attributed (annotated) methods with
>> base-class-first strategy.
>> If a single class contains multiple methods marked with same
>> attribute, the order is whichever way they are returned by reflection
>> (this is checked only once - during code generation, once code is
>> generated, the order will always be the same).
>>
>> One very good thing (which you pointed out in the old e-mail) is that
>> attributed (annotated) methods can have parameter injections, and if
>> these injected values are used *only* in the lifecycle stage indicated
>> by attribute (annotation), then you don't need to have these
>> injections in fields.
>>
>>>
>>> Cheers
>


Mime
View raw message