Functional reactive programming in C# for WPF

I've been working on a library to wrap WPF dependency properties with signals so that data binding is easier to do in WPF when using C#:

http://www.codeplex.com/wpfsignals.

Dependency properties by themselves are like signals (time-varying values) but don't support direct transformation (i.e., map) or composition like signals do. Instead, you have to define verbose value converters and jump through a lot of hoops. To solve this problem, the WPF signal library creates a signal-like wrapper around dependency properties so they can support direct transformation and composition; e.g., we can directly express relationships like:

rectangle().top().bind = canvas.height() - rectangle.height()

meaning that the rectangle is stuck to the bottom of the canvas, even as the size of the canvas or rectangle changes.

This is currently a source code release only. SignalLib is a Visual Studio 2008 .NET 3.5 project, and an example application (in the SignalExample project) is provided to help introduce the library. Feedback is appreciated.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

I like 1. Can fields be

Neato!

1. Can fields be rebound

which leads to..

2. How does "undo"ing mix with default/unspecified values?

ex:


o.a.bind() = time()
o.d.bind() = time()
(o.a() + o.b() + o.c()).bind() = o.d()

where b, c have some default property that wasn't explicitly set

(I like the idea as it is a little closer to constraint systems.. I'm curious if you have any other documentation on that feature)

3. How are collections dealt with, and if you permit them, terms of type signal signal 'a ?

anyways, interesting direction :)

1. Yes, creating a binding

1. Yes, creating a binding is a simple imperative statement (this is still C#!). So

rect.position().bind = new Point(100,100);
rect.position().bind = new Point(200,200);

The latter statement is in effect (a signal can only be bound once).

Actually, this is a very simple wrapper around WPF's dependency properties. So in WPF, the current value of a dependency property is

(a) its default value,
(b) its bound value,
(c) its explicitly set value, and
(d) its animated value,

Where (d) has a higher priority than (a). Since signals here wrap dependency properties, they will provide whatever value is the current observed value of the dependency property. Actually, the signal library allows us to express (b), (c) and (d) ((a) can only be expressed when the dependency property is defined), e.g.,

// (d) move rectangle to 100,100 in 1 second
rect.position().animateTo(new Point(100,100));
// (c) make rectangle's position 100,100 NOW
rect.position().value = new Point(100,100);
// (b) ensure that rectangle's position is always 100,100
rect.position().bind = (new Point(100,100)).constant();

I prefer using mostly (b) in my programs, while animation originates from one animated "clock" signal. Priorities can be a pain sometime as animations remain in effect even after they have reached their destination value! For that reason, you can also "stop" an animated signal so you can set its value:

rect.position().stop();

You can clear the value of a signal so its binding will be used:

rect.position().clearValue();

Or you can clear a binding so the default value will be used:

rect.position().clearBinding();

A bit complicated because we are wrapping WPF vs. defining our own signal construct from scratch.

2.

The combinations I allow are very simple, there is no real constraint system. So for:

(o.a() + o.b() + o.c()).bind = o.d()

The value of o.d() - o.b() - o.c() will be stuffed into o.a(). If we rewrite the expression to have o.b() first, it will go in o.b() instead. This was done as a convenience so that we can write things like:

(rect.position() + rect.center()).bind = new Point(100,100).constant(); 

What is interesting is if you instead write:

(rect.center() + rect.position()).bind = new Point(100,100).constant(); 

Now, this is equivalent to

rect.center().bind = new Point(100,100).constant() - rect.position();

This would basically resize rectangle instead of repositioning to ensure that rect is still in the center!

3. we don't deal with

3. we don't deal with collections yet. .NET has an observable collection class + there is LINQ. We might be able to build something on top of that. But for now there hasn't been a strong need. No Signal either, actually, I'm not sure if/how WPF can support that.

Really cool

I looked at writing an FRP library in C# awhile back, but got diverted by something else before I could understand it well enough to get working code. I've always thought FRP was a prime candidate for web programming instead of ASP.NET. Such a framework should remove a great deal of the redundant control flow logic that I'm forced to deal with on a daily basis. Maybe one day. :-)

This is just for WPF (around

This is just for WPF (around dependency properties), the library could also easily be ported to Silverlight or Windows workflow/WWF (which are also based on dependency properties).

I didn't actually implement signals for C#, I'm just bringing out the best in dependency properties :)

I do most of my simple UIs

I do most of my simple UIs in Flapjax nowadays (though perhaps largely because of $B !) - doing a stripped down version with browser testing wouldn't take too long.

updated signal library to WPF Bling

I've been redoing some of the signal infrastructure to better suit the needs of UI programming. Also, I've added a related DSL to write WPF pixel shader effects in pure C#! This is really cool as it makes the GPU programming very accessible (I got the idea from the Haskell GPU thread that mentioned Brahma).

Two things I've learned:

  • To build a lightweight domain specific language, you really don't need meta-programming, just extension methods and some operator overloading. There are drawbacks: you have to write lots of wrapper code to enable functionality, and sometimes your types aren't good enough (e.g., user must explicitly convert Signal into DoubleSg).
  • There seems to be a connection between GPU programming and FRP. Whereas signals are time-varying values, pixel shaders benefit from space-varying values (ala array programming, not just comprehensions). Anyways, I want to explore this connection in my future research.

The project URL has changed:

http://www.codeplex/com/bling

I've added support for

I've added support for Direct3D borrowing some ideas from Conal's Vertigo work. Here is a URL on a blogpost explaining how it works:

http://mcdirmid.wordpress.com/2009/07/20/functional-graphics-in-c/

Reactive framework for .Net

Microsoft is including something similar in .Net 4.0, or at least as a library you can download. It's called the Rx framework.