PostSharpin’ – Part 3

In the final part of this series I look at new features coming in PostSharp 3.2, including support for aggregates and undo/redo.

Aggregates

Under the hood, the biggest new feature in 3.2 might be the support for aggregates: object graphs with parent-child relationships. Version 3.2 makes aggregates first class citizens in the world of PostSharp aspects, and allows PostSharp to offer more complex features like undo/redo. They’ve also modified other aspects to be aggregate aware – so for example the Actor aspect now also implements IAggregatable.

You mark up properties in your aggregatable types with Child, Parent and Reference aspects, and PostSharp then does the right thing when dealing with your object graph. I mentioned an “aggregatable type” – you can mark up your class with the Aggregatable aspect, but on its on this won’t do much. Instead you’ll use another instance-level aspect – such as Recordable, Immutable, Disposable, and others – which are all aggregate aware and will work correctly with your object graph.

If you’re using Entity Framework, nHibernate, or similar, these frameworks already understand your graph and its relationships, so additional markup may feel like more work, although these aspects could open the door to custom aspects which understand both the data services layer and composition of your model.

Here’s a simple example of aggregates with the new Disposable aspect, which handles the dirty work of implementing IDisposable on types in your graph.

using PostSharp.Patterns.Collections;
using PostSharp.Patterns.Model;

[Disposable]
public class Order
{
    public Order()
    {
        Details = new AdvisableCollection<OrderDetail>();
    }

    public int Id { get; set; }
    public DateTime OrderDate { get; set; }
    public string Customer { get; set; }
    
    [Child]
    public ICollection<OrderDetail> Details { get; private set; }
}

[Disposable]
public class OrderDetail
{
    public int Id { get; set; }
    public string Product { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
} 

The child collection must be of type AdvisableCollection, otherwise PostSharp raises a runtime error. But once defined correctly, when the parent is disposed PostSharp will dispose of all children too.

A bit irritating, though, is that to use your parent type in a using statement you must initialize it outside the scope of the using to avoid the build-time error type used in a using statement must be implicitly convertible to System.IDisposable:

var order = new Order { Id = 1, OrderDate = DateTime.Now };
using (order as IDisposable)
{
   ...
}

Immutable and Freezable

I was initially excited to see that PostSharp will be adding Immutable and Freezable aspects in version 3.2.

When you need to support thread-safe access for a number of object types, the idea of immutable types is really appealing. But also attractive is the use of object initializers. Unfortunately, since object initializers require public setters the type can’t be immutable. Named constructor parameters can partially solve the issue, but the brevity of object initializers, for both the caller and callee, can’t be beat. Fortunately, C# 6.0 should make writing immutable types easier with the new primary constructors and property initializers, but I was hoping that PostSharp could work some magic here right now, without having to wait for the C# release. Well, this may be a pipe dream of mine. PostSharp will be adding support for early and late object initialization through Immutable and Freezable, but these address the problem with regard to object graphs and “deep” immutability. Granted, this will be a helpful feature. Unfortunately, I wasn’t able to get these aspects working correctly with the alpha code so I’ll have to try again later.
Edit: Per Gael Fraiteur’s recommendation, an upgrade to version 3.2.20-alpha got this working. As hoped, PostSharp will raise an ObjectReadOnlyException if you try to make any changes to an Immutable type after construction or a Freezable type after Freeze is called. This works for both simple and “deep” fields and properties. I expect “freezability” to be especially useful.

These aspects are available from the pre-release version of the PostSharp Threading Pattern Library. A more thorough discussion of these aspects is available here.

Recordable

Now here is something to get excited about. Implementing the Memento pattern on your own is usually hard, error prone, and non-performant; probably the reason why so few applications and frameworks support it, but also making it a great candidate for an AOP approach.

The Recordable aspect builds upon the support for aggregation, so with a few simple changes to the code above I’m ready for Undo/Redo support:

using PostSharp.Patterns.Collections;
using PostSharp.Patterns.Model;
using PostSharp.Patterns.Recording;

[Recordable]
public class Order
{
    public Order()
    {
        Details = new AdvisableCollection<OrderDetail>();
    }

    public int Id { get; set; }
    public DateTime OrderDate { get; set; }
    public string Customer { get; set; }

    [Child]
    public ICollection<OrderDetail> Details { get; private set; }
}

[Recordable]
public class OrderDetail
{
    public int Id { get; set; }
    public string Product { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
}

As before, the child collection must be an AdvisableCollection, otherwise an error is thrown.

Once a type, or the types in an object graph, are made recordable, you then use the new RecordingServices features. The Recorder tracks operations within a scope and provides undo/redo functions. There’s a default Recorder, RecordingServices.DefaultRecorder, to get started or for simple applications.

By default, every change to a property or field, add/remove from a child collection, or call to a public method on the class, is atomic. To bundle these into a scope – a logical operation – you use a RecordingScope, which can be set either declaratively or programmatically.

For example:

var order = new Order();
using (RecordingScope scope = RecordingServices.DefaultRecorder.OpenScope(RecordingScopeOption.Atomic))
{
    order.Customer = "Bikes R Us";
    order.Id = 1;
    order.OrderDate = DateTime.Now;
}

If Undo were called after the above, the Order object would be returned to its default state after construction.

It’s worth noting that using an object initializer is not an atomic operation. For example the following will undo the last property set operation (the set of OrderDate):

  var order = new Order { Customer = "Bikes R Us", Id = 1, OrderDate = DateTime.Now };
  RecordingServices.DefaultRecorder.Undo();

Also notable is the factoid that constructors do not participate in an operation, even if the constructor sets properties or fields within the class; the object must be initialized before it can be considered recordable.

Along with Undo is of course Redo.

Here we create a new Order and OrderDetail, Undo the add of the detail line to the order, and then immediately have a change of heart and call Redo to restore the added line:

var order = new Order { Customer = "My Grocer", Id = 1, OrderDate = DateTime.Now };
var od = new OrderDetail { Id = 1, Product = "pears", Quantity = 10, UnitPrice = 1.99M };
order.Details.Add(od);
RecordingServices.DefaultRecorder.Undo();
RecordingServices.DefaultRecorder.Redo();

Restore points are supported too:

var order = new Order { Customer = "My Grocer", Id = 1, OrderDate = DateTime.Now };
RecordingServices.DefaultRecorder.Clear();

var token1 = RecordingServices.DefaultRecorder.AddRestorePoint("first");
order.Details.Add(new OrderDetail { Id = 1, Product = "apples", Quantity = 5, UnitPrice = 1.99M });

var token2 = RecordingServices.DefaultRecorder.AddRestorePoint("second");
order.Details.Add(new OrderDetail { Id = 2, Product = "potatoes", Quantity = 10, UnitPrice = .99M });

// Removes detail 2
RecordingServices.DefaultRecorder.UndoTo(token2);

// Removes detail 1
RecordingServices.DefaultRecorder.UndoTo(token1);

You have a great deal of control over the Recorder and other recordable features, and in general the implementation looks full-featured and quite useful. There’s also a series of blog posts on the PostSharp site with more detailed information.

The recordable feature is available in the pre-release version of the PostSharp Model Pattern Library.

Advertisements

PostSharpin’ Part 2 – Actor

In Part 1 I looked at PostSharp’s support for INotifyPropertyChanged, and several handy aspects to help with threading: Background, Dispatch, ThreadUnsafe and ReaderWriterSynchronized. In part 2 I’d planned to look at PostSharp’s Actor support and new features for undo/redo, but life got in the way, so part 2 will cover only the Actor aspect, and part 3 will cover new features in PostSharp 3.2.

Actor

The Actor model hasn’t yet received a lot of attention in the .NET world. The model was first defined in 1973 as a means to model parallel and distributed systems, “a framework for reasoning about concurrency.” The model assumes that “concurrency is hard” and provides an alternative to do-it-yourself threading and locking. It’s built into languages like Erlang and Scala, and there are a number of libraries and frameworks. It’s gotten a recent boost in the .NET world with F# agents, the TPL Dataflow library and Project Orleans.

Conceptually, an actor is a concurrency primitive which can both send and receive messages and create other actors, all completely asynchronous, and thread-safe by design. An actor may or may not hold state, but it is never shared.

Where does PostSharp fit in? Remembering the PostSharp promise: “Eradicate boilerplate. Raise abstraction. Enforce good design.” the PostSharp Actor implementation allows developers to work at the “right” level of abstraction, and provides both build time and run time validation to avoid shared mutable state and ensure that private state is accessed by only a single thread at a time.

To use the Actor aspect, install the Threading Pattern Library package from NuGet.

Ping Pong

I started with the PingPong sample (well, PingPing really) from PostSharp. Here’s the code:

[Actor]
public class Player 
{
    private string name;
    private int counter;

    public Player(string name)
    {
        this.name = name;
    }

    public async Task Ping(Player peer, int countdown)
    {
        Console.WriteLine("{0}.Ping({1}) from thread {2}", this.name, countdown,
                          Thread.CurrentThread.ManagedThreadId);

        if (countdown > 1)
        {
            await peer.Ping(this, countdown - 1);
        }

        this.counter++;
    }

    public async Task GetCounter()
    {
        return this.counter;
    }
}

class Program
{
    static void Main(string[] args)
    {
        AsyncMain().Wait();
        Console.ReadLine();
    }

    private static async Task AsyncMain()
    {
        Console.WriteLine("main thread is {0}", Thread.CurrentThread.ManagedThr

        Player ping = new Player("Sarkozy");
        Player pong = new Player("Hollande");

        Task pingTask = ping.Ping(pong, 10);

        await pingTask;

        Console.WriteLine("{0} Counter={1}", ping, await ping.GetCounter());
        Console.WriteLine("{0} Counter={1}", pong, await pong.GetCounter());
    }
}

Here the Player class is an actor, and decorated with the PostSharp Actor aspect. The “messages” are implied by the Ping and GetCounter async methods. Whether the “message-ness” of the actor model should be abstracted away is certainly a point for discussion, but it does provide for easier programming within an OO language like C#.

From the output we see that 1) activation (construction) is performed on the caller’s thread, 2) the player’s methods are invoked on background threads, and 3) there is no thread affinity.
pingpong_sm

Validation

The compile-time validation performed when using the Actor aspect tries to ensure you do the right thing.

1. All fields must be private, and private state must not be made available to other threads or actors.

If we try to define the name field as public:

[Actor]
public class Player 
{
    public string name;
    private int counter;
    ...
} 

This results in the compiler error: Field Player.name cannot be public because its declaring class Player implements its threading model does not allow it. Apply the [ExplicitlySynchronized] custom attribute to this field to opt out from this rule.

The same holds true of a public property:

[Actor]
public class Player 
{
    ...
    public int Id { get; private set; }
    ...
}

This results in the compile-time error: Method Player cannot return a value or have out/ref parameters because its declaring class derives from Actor and the method can be invoked from outside the actor.

2. All methods must be asynchronous.

To PostSharp this means that method signatures must include the async modifier. If you try to return a Task from a non-async method, something like this:

 public Task<string> SayHello(string greeting)
 {
     return Task.FromResult("You said: '" + greeting + "', I say: Hello!");
 }

You’ll get a compiler error: Method Player cannot return a value or have out/ref parameters because its declaring class derives from Actor and the method can be invoked from outside the actor.

The async rule also means that you must ignore the standard compiler warning about using async when you don’t demonstrably need to, which is why the GetCounter method looks like this:

public async Task<int> GetCounter()
{
    return this.counter;
}

PostSharp will dispatch the method to a background task, so you should ignore the compiler warning: This async method lacks ‘await’ operators and will run synchronously. Consider using the ‘await’ operator to await non-blocking API calls, or ‘await Task.Run(…)’ to do CPU-bound work on a background thread.

If you remove the async modifier the Actor validation will fail. You can add an await, but it looks silly, and you shouldn’t await Task.FromResult anyway:

public async Task<int> GetCounter()
{
    return await Task.FromResult<int>(this.counter);
}

You can, however, write a synchronous method, which PostSharp will dispatch to a background thread. For example:

public void Ping(Player peer, int countdown)
{
    Console.WriteLine("{0}.Ping from thread {1}", this.name,
                      Thread.CurrentThread.ManagedThreadId);

    if (countdown >= 1)
    {
        peer.Pong(this, countdown - 1);
    }

    this.counter++;
}

This may be a good thing, but also possibly misleading, since at first glance a developer might assume the method is executed synchronously on the current thread.

Rock-Paper-Scissors

Next I tried the “Rock-Paper-Scissors” example as described here.

Here’s my implementation.

namespace Roshambo
{
    public enum Move
    {
        Rock,
        Paper,
        Scissors
    }

    [Actor]
    public class Coordinator
    {
        public async Task Start(Player player1, Player player2, int numberOfThrows)
        {
            Task.WaitAll(player1.Start(), Task.Delay(10), player2.Start());

            while (numberOfThrows-- > 0)
            {
                var move1Task = player1.Throw();
                var move2Task = player2.Throw();
                Task.WaitAll(move1Task, move2Task);

                var move1 = move1Task.Result;
                var move2 = move2Task.Result;

                if (Tie(move1, move2))
                {
                    Console.WriteLine("Player1: {0}, Player2: {1} - Tie!", move1, move2);
                }
                else
                {
                    Console.WriteLine("Player1: {0}, Player2: {1} - Player{2} wins!", move1, move2,
                        FirstWins(move1, move2) ? "1" : "2");
                }
            }
        }

        private bool Tie (Move m1, Move m2) {
            return m1 == m2;
        }

        private bool FirstWins(Move m1, Move m2)
        {
            return
              (m1 == Move.Rock && m2 == Move.Scissors) ||
              (m1 == Move.Paper && m2 == Move.Rock) ||
              (m1 == Move.Scissors && m2 == Move.Paper);
        }

    }

    [Actor]
    public class Player
    {
        private Random _random;
        private string _name;

        public Player(string name)
        {
            _name = name;
        }
        public async Task Start()
        {
            int seed = Environment.TickCount + System.Threading.Thread.CurrentThread.ManagedThreadId;
            _random = new Random(seed);
        }

        public async Task<Move> Throw()
        {
            return (Move)_random.Next(3);
        }

        public async Task<string> GetName()
        {
            return _name;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        AsyncMain().Wait();
        Console.ReadLine();
    }

    private static async Task AsyncMain()
    {
        var coordinator = new Coordinator();
        var player1 = new Player("adam");
        var player2 = new Player("zoe");

        await coordinator.Start(player1, player2, 20);
    }
}

And the exciting results:
rps

A few things to note:

  • I passed a name to the Player constructor but then never used it again. As private state, to access the name you must follow the Actor message rules and use an async method. I wouldn’t want the Coordinator to repeatedly ask each Player for its name, but this could have been done once at play start.
  • Trying to uniquely seed a System.Random instance for each player was tricky, and my implementation is a hack. The Random class is not thread-safe, so while sharing a single static Random instance among Player actors is an option, having to perform my own locking around Random.Next calls seemed to violate the spirit of the actor model. The default seed for a Random instance is Environment.TickCount, which if called in close succession will likely return the same value. Using the current thread id as a seed is an alternative, but although PostSharp will ensure that Actor methods will be called on a background thread, there’s no assurance they’ll be different threads for different actor instances. My not-so-robust compromise was to take the sum of TickCount and thread id and cross my fingers. Including the dummy Task.Delay when waiting for the players to start helps.
  • The Coordinator here does not hold state, and its Start method will 1) tell the players to start, 2) tell the players to throw, and 3) announce the result.
  • The Player does hold non-shared state, and contains Start, Throw and GetName async methods. None of these methods is inherently asynchronous, so I see compiler warnings telling me to consider using the await operator. I could have made these methods synchronous, but as I said above I think it leads to some cognitive dissonance between the code you see and the underlying actor implementation.

Summary

Overall, despite some quirks, using the Actor aspect could be useful. It would be interesting to compare PostSharp’s Actor support with other .NET implementations, and I may try that some day.