Stability of trunk as of 55127

Feb 7, 2011 at 4:25 AM

Is the trunk considered to be production ready?  We've been using 33016.

Feb 7, 2011 at 11:26 PM

No, it is not yet production ready.

Main targets for the next release (V2) are robust exception handling. All collection transformations should be able to handle changes in atmost O(log n) time (mainly by using skiplists, a version of binary trees).

Optional targets are adding extensions via config file and splitting obtics library in two. 1 for values and 1 for object linq (as an extension).

Obtics has aquired quite a sizable code base. As you can imagine it is quite a bit of work to get it all done. If you would like a stable release soon, lend a hand.



Feb 8, 2011 at 12:24 AM

To be honest, I find the Obtics code base to be quite overwhelming, despite having contributed significant amounts of code to many other open source projects.   The deeply nested call hierarchies with mysterious locking and cryptic class names have foiled my attempts to make much progress in improving things.  Perhaps some architectural diagrams or other documentation would help light up understanding for those who have time to contribute.  It seems like the barrier to entry is exceptionally high. :(

Feb 8, 2011 at 10:22 AM

Right; it is valid critique you are giving.  So another reason I could use some help is to stop me blabbering in my own private dialect. I guess if you spend too much time in your own code both 'Tart' and 'Turd' seem perfect synonymes for 'Cake' and instead of a cooky factory you end up with a pile of ..   :-/

I should spend some time and do what programmers love to do... Document.


Feb 8, 2011 at 7:00 PM

Maybe we can start a bit of a dialog to try and bridge the gap.

Obtics takes an expression and decomposes it into pieces, for example we might have:

a + b

Now, I'm assuming there would be an Obtics object somewhere that basically takes a and b, observes them, and then whenever a change happens, it recomputes the result and fires its own property changed.  Is this assumption true?  If so, what would this object be called?

Similarly there are a bunch of Linq operations, such as:


When l1 or l2 change, a result list is modified.  What would be the object that handles this operation?

Presumably, the objects that handle the operations like a + b and l1.Concat(l1) have a name associated with them.  What is this name in Obtics?


Once you have the objects handling the operations, they are presumably composed in some manner and they can pull values from each other.  What's the mechanism for this composition?  What classes are involved?

What does the general flow of events look like from a high level?

Feb 8, 2011 at 11:44 PM


Obtics basicly consists of 3 layers.

The first layer are those classes whose instances do the actual grunt work. These classes take one or more 'sources' being an observable value or collection and have one or more clients. Together with some helper classes these are the 'Transformation' classes. Each Transformation class provides a 'transformed' view of it's source. What it means it takes the source values or collections, does some calculation with it and presents the result. What they also do is that when a source sends a change notification they check if it is relevant and if it is, propagate this notification to it's clients.

The Transformation classes can be found in the Obtics.Collections.Transformations namespace (for collection transformations) and the Obtics.Values.Transformations namespace (for value transformations).

Each Transformation object can be client or source for other Transformation objects. All these transformation objects working together allow for complex transformation graphs. I often call them transformation pipelines. The a + b example would probably consist of 2 PropertyTransformation objects for reading and listening for changes on the individual properties and one BinaryTransformation doing the '+' operation.

The second layer are those methods that create instances of the Transformation classes and glue them together into transformation pipelines or graphs. These methods are implemented as extension methods and for collections they map directly to the object linq methods. For value transformations they are extension methods on the IValueProvider interface and defined in the Obtics.Values.ValueProvider class. For object linq (collection transformations) they are defined in Obtics.Collections.ObservableEnumerable class.

Your o.a + o.b example could be expressed as ValueProvider.Select( ValueProvider.Property<O,int>(o,"a"), ValueProvider.Property<O,int>(o,"b"), (aValue, bValue) => aValue + bValue). Executing this expression would result in two PropertyTransformation objects and one BinarySelectTransformation object.

The third layer is the Obtics.Values.ExpressionObserver. It takes a lambda expression and rewrites it into calls to the mentioned extension methods. In this process each value becomes an IValueProvider. Note that the ExpressionObserver is in the Obtics.Values namespace. This is technically correct since the hard work is in rewriting value expressions. An int value becomes an IValueProvider<int>. This requires complex rewriting of the expression. An IEnumerable<int> remaines an IEnumerable<int>. The IEnumerable becomes observable simply because the System.Linq.Enumerable methods are directly replaced with the Obtics.Collections.ObservableEnumerable methods.

So ExpressonObserver.Rewrite((O o) => o.a + o.b) would become something like (O o) => ValueProvider.Select( ValueProvider.Property<O,int>(o,"a"), ValueProvider.Property<O,int>(o,"b"), (p1, p2) => p1 + p2) which would be a Func<O,IValueProvider<int>>

ExpresionObserver.Rewrite((O o) =>o.l1.Concat(o.l2)) would become (O o) => ValueProvider.Select( ValueProvider.Propert<O, IEnumerable<int>>(o,"l1"), ValueProvider.Property<O.IEnumerable<int>>(o,"l2"), (p1, p2) => ObservableEnumerable.Concat(p1,p2)) which would be a Func<O,IValueProvider<IEnumerable<int>>>

Hope this sheds some light,