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