Home Closet Obtics – Functional Reactive Programming on .Net

Obtics – Functional Reactive Programming on .Net

by admin

This article is a translation of Obtics project home page on Codeplex With minor changes.

Project description

The purpose of thisproject is to create a library that applies the principles of functional reactive programming (FRP) in.Net.
In FRP, your calculations automatically respond to changes inthe data used in them.

History

The idea for thisproject came about while working on a large administrative application usingXAML to describe the interface. This application had extensive data and view domain models.
One of the problems was that it is quite difficult to determine when the view(s) should be updated. Simply recalculating the whole view with every user action is not a good enough idea, because it takes too much time and, in addition, the data could be updated by some background process.
As a solution, I created a set of transducers that created objects that tracked changes in their source with the ability to update the calculated data. I found thisconcept to be very useful, since you no longer have to subscribe and unsubscribe to events or remember to update controls when a click event occurs. All you have to do is label the dependencies and specify how the result should be calculated.
WPF binding was not a good option for this task because :

  • Targets for binding must necessarily be properties of a classthat inherits a DependencyObject.
  • Binding doesn’t work so well with observablecollections.
  • Binding can’t be easily applied to more complex transformations. They will always require a DependencyObject as an intermediate step.

Although I thought the collection conversions were really useful, the idea almost immediately failed for the following reasons :

  1. Using them required extra words in the code, which made it hard to understand for people who weren’t familiar with the technology. And while code like "register-event-handler-update" was actually more complicated, it remained easier to read for my colleagues.
  2. The objects ran completely asynchronously, and each had its own message queue and buffer, which made them quite "heavy". Because of their success, they were often used in a project and therefore placed a significant load on the application.
  3. Debugging pipeline transformations in a classical debugger becomes very difficult. It’s no longer so easy to trace the update process stepby step.

This experience led me to clarify some additional requirements for the next version of the conversion objects :

  • Their use should be simple (must use LINQ for transformation and static methods).
  • They should be as easy as possible.
  • The use of objects should happen without affecting the rest of the code and without interfering with existing libraries (extending LINQ, not replacing it).
  • For debugging, I recommend usingother methods such as Unit Testing. The idea is to trust the conversion process to the library, as I come to the conclusion that this process cannot be properly mapped by the tracer.

Features

Obtics allows you to create reactive and observable objects, freeing you fromhaving to update the result and keeping track of when you need to update the result in a dynamic application. By being able to worry less about this, you can create richer and more robust applications faster.

Less abstract

A simple piece of code like the one below will produce static results using the standard Object LINQ. If you add a bind to the PeopleNames property fromXAML, you will geta "one-time" result, regardless of how you modify the _Peoplecollection. Using Obtics, the PeopleNames result will be fully reactive and observable. This means :

  1. When the _People collection or the LastName property of an individual People object is changed, the value of PeopleNames will be automatically updated (reactivity).
  2. Your bound XAML application will show changes to PeopleNames automatically (observability).

public class Test
{
ObservableCollection<Person> _People;
public IEnumerable < string > PeoplesNames_Static
{
get
{
return
from p in _People
orderby p.LastName
select p.LastName;
}
}
public IEnumerable < string > PeoplesNames
{
get
{
return
ExpressionObserver.Execute(
this ,
t =>
from p in t._People
orderby p.LastName
select p.LastName
).Cascade();
}
}
}
* This source code was highlighted with Source Code Highlighter

With Obtics you can write the code below and bind to the Value value of the FullName property. Any changes to the LastName or FirstName properties will be automatically and immediately displayed in the application.

public class Test
{
Person _Person;
public IValueProvider< string > FullName
{ get { return ExpressionObserver.Execute( this , t => t._Person.LastName + ", " + t._Person.FirstName);}}
}
* This source code was highlighted with Source Code Highlighter

(The Person classin these examples is an observable class. This means that an instance of this class sends change notifications every time a property value changes. Read more at here )

Transformation types

Implicit value conversions.

The methods used form the Obtics.Values.ExpressionObserver class. Simply write a lambda function that returns the desired result, ExpressionObserver will analyze it, extract all dependencies, and create an expression that is fully reactive when you change any observable value on which the expression depends. This will automatically rewrite the standard Object LINQ into a reactive and observable form, which is a very convenient way to create bindableobject LINQ queries.

using Obtics.Values;
class Test
{
Person _Person = new Person( "Glenn" , "Miller" );
Person Person
{ get { return _Person; }}
public IValueProvider< int > PersonFullNameLength
{
get
{
return
ExpressionObserver.Execute( this , t => t.Person.FirstName.Length + t.Person.LastName.Length + 1);
//the below line is even simpler but because the lambda expression depends on the external 'this' variable the
//expression is re-compiled for every Testclass instance. Better use lambda's without external variables.
//returnExpressionObserver.Execute(() => Person.FirstName.Length + Person.LastName.Length + 1);
}
}
}
* This source code was highlighted with Source Code Highlighter

Explicit value conversions.

Methods from Obtics.Values.ValueProvider class are used. You can build your own transformation pipeline by specifying your own methods, which makes it easy to control the transformation process. You can specify exactly those transformable values that correspond to your computations, so you can prevent wasting resources on immutable or unobservable dependencies. This approach can be useful when working with large amounts of data.

using Obtics.Values;
class Test
{
Person _Person = new Person( "Glenn" , "Miller" );
Person Person
{ get { return _Person; } }
public IValueProvider< int > PersonFirstNameLength
{
get
{
return
//selectthe never changing Person property make a (static) IValueProvider for it.
ValueProvider.Static(Person)
//selectthe FirstName property of Person.This is a classic
//property and observably mutable
Property<Person, string > (Person.FirstNamePropertyName)
//Calculate the result
Select(
//fn is a stringand Length is an
//immutable property of string
fn => fn.Length
);
}
}
}
* This source code was highlighted with Source Code Highlighter

Collection transformations (LINQ).

Methods fromObtics.Collections.ObservableEnumerable are used. As with explicit conversions, this approach allows you to specify exactly how your collection will respond. This will make usingthe library more complicated, but you can manually describe transformations and be notified of dependencies that need to be monitored for changes. Which allows you to prevent wasting resources on dependencies that will never be changed. This style can be useful when working with large collections to prevent unnecessary resource consumption. To getthe full benefit of usingthis method, you must replace "usingSystem.Linq;" with "usingObtics.Collections;" inyour code, otherwise many errors will occur.

using SL = System.Linq;
using Obtics.Values;
using Obtics.Collections;
class Test
{
ObservableCollection<Person> _People= new ObservableCollection<Person> ();
public ReadOnlyObservableCollection<Person> People
{ get { return new ReadOnlyObservableCollection<Person> (_People); }}
public IEnumerable < string > LastNames
{
get
{
return
from p in People
select ValueProvider.Static(p).Property<Person, string > ( "LastName" ) into ln
orderby ln
select ln;
}
}
}
* This source code was highlighted with Source Code Highlighter

ExpressionObserver (implicit transformations) is extensible. A library has been created ( ObticsToXml ), which builds on its extension and allows you to create fully dynamic Linq toXML expressions.
Obtiss offers fully reviewed support for all of ObjectLinq and most of Linq to XML
More examples can be seen at these links : Transformation Examples , ObticsExaml and ObticsRaytracer
Project ObticsWpfHelper contains a solution based on a partial combination of Obtics and WPF.
It is very important that functions, lambda expressions, values, and objects that are used with Obtics behave as expected of them.

Future possibilities

Version 2.0 is on its way. Plans for future versions :

  • Two way operation (two way operation). All transformations will support both source-to-client changes and vice versa. Developers will be able to specify the reverse path, allowing automatic changes from client to source to be applied.
  • Lightweight version for web (Silverlight) and mobile devices. Lots of code focused on distributing changes from source to client. It’s possible to create a version that doesn’t use collection change notifications, but can notify of property changes. Which should look good when working with small collections.
  • Obtics should be easily supported by F#.

Project Website : http://obtics.codeplex.com/

You may also like