ReviewUmbrella project
The Umbrella project from nVentive. I had the chance of sitting with Francois Tanguay in DevTeach and he showed me a bit about it. I was impressed. Umbrella is the ultimate utility library, using all the advantages C# 3.0 can give it. In fact, I think of it a bit like boost for C#.
I tried to read the code, and it was hard. Because of the util nature of Umbrella, there isn't a lot of context around the code, so you have to parse the code to understand what it is doing. Luckily, there are a lot of unit tests, which allows me to get the context. I strongly recommend reading the tests in stead of the code, they are a far better way to get an understanding on what the project can offer.
I'll go with my usual style, top to bottom, and review what I can.
Binding
This is a concept that I am familiar with from boost. It is also called memoization currying, and is used frequently in functional languages. Here are a few tests, which would explain it much better:
[Fact] public void Bind_With_One_Param() { Func<int, int> echo = (i) => i; var always10 = echo.Bind(10); Assert.Equal(10, always10()); } [Fact] public void Bind_First_With_Two_Params() { Func<double, double, double> power = Math.Pow; var twoToTheN = power.BindFirst(2.0); Assert.Equal(1024.0, twoToTheN(10.0)); }[Fact] public void Bind_Chaining() { Func<int, int, int, int, long> func = (a, b, c, d) => a + b + c + d; var chain = func.BindFirst(1).BindFirst(2).BindFirst(3).Bind(4); Assert.Equal(func(1, 2, 3, 4), chain()); }
If you are working with delegates a lot, this is a really nice way to handle that.
Clock
This is a simple abstraction (IClock, SystemClock, FreezedClock) over the current time, which allows you to play around with time with total disregard to the system time. Basically, an abstraction on top of DateTime.Now. The main goal is usually to enable unit testing, but I have found this approach to be very useful for handling out of time processing. What does this mean? If I want to process payroll for February, I should be able to do so, and all calculations should be set to whatever date I am talking about, not the current date. (In fact, in such systems, there is usually the target date and effective date, both of which are used to calculate various things, but I digress.)
Collections
Collections are important, no doubt about that, and Umbrella has a lot to offer there. The first interesting example is automatic conversion between types, supported by the CollectionAdapter. Here is the test that shows how this works:
[Fact] public void CanConvertBetweenCollectionsTypes() { var ints = new List<int>(); ICollection<string> strings = new CollectionAdapter<int, string>( ints, Funcs<string, int>.Convert, Funcs<int, string>.Convert); strings.Add("1"); Assert.Equal(1, ints[0]); }
Note the Funcs.Convert calls, we will discuss them later. The abstraction is quite complete and very useful. This is also a good way of implementing covariance with generics, I think.
There is a wealth of extension methods for dealing with collections. The most important one, as far as I am concerned, is the AddRange over ICollection<T>. I keep wanting that, and it is only there for List<T>. Having it as an extension method is sweet.
[Fact] public void AddRange_And_ReplaceWith() { ICollection<int> collection = new List<int>();collection.AddRange(new int[] { 1, 2 }); collection.ReplaceWith(new int[] { 3, 4 }); Assert.Equal(2, collection.Count); Assert.Equal(3, collection.ElementAt(0)); Assert.Equal(4, collection.ElementAt(1)); }
Another interesting extension method is Subscribe. I don't like the name, because it has nothing to do with what the code does, but it is a really nice idea nonetheless:
[Fact] public void Subscribe() { using (collection.Subscribe(1)) { Assert.Equal(1, collection.Count); } Assert.Empty(collection); }
Inside the using block, the collection has the element, but during dispose, it is removed. I think that the reason it is called this way is that it is being used by ObservableExtensions (later).
Dictionary also get some love, with FindOrCreate and GetValueOrDefault, both of which are very welcome. Enumerable get a much needed ForEach extension method, as well as other interesting bits, ranging from bool None(predicate) to checking if it is empty to IndexOf, etc. LazyList make an appearance, as it should.
What I find very interesting is SyncronizedDictionary. It is interesting because of the way it is implemented, and because dictionaries are almost always a source of hard to realize threading issues in many applications. The implementation made me laugh, however:
public TValue this[TKey key] { get { return Lock.Read(item => item[key]); } set { Lock.Write(item => item[key] = value); } }
It made me laugh because it is so simple. I traced down the implementation, and I liked it. It comes down to using Reader Writer Lock, which is what you are supposed to be doing. Obvious Umbrella has attained its critical mass.
Components
Ubmrella is also big enough to include its own Service Locator implementation, which can be plugged into an IoC container. I think that I'll skip this part.
Composites
All the building blocks for the composite patterns are here, and in a very interesting fashion. Take a look at this:
public class CompositeFoo : Composite<IFoo>, IFoo { #region IFoo Members public void Do(int i) { Items.ForEach(item => item.Do(i)); } #endregion }
And now we can use this like this:
[Fact] public void SelectMany() { var foo = new CompositeFoo { new Foo(), new OtherFoo(), new OtherFoo(), new CompositeFoo { new Foo(), new OtherFoo() } }; IEnumerable<IFoo> items = foo.SelectMany(); Assert.Equal(5, items.Count()); Assert.Equal(2, items.OfType<Foo>().Count()); Assert.Equal(3, items.OfType<OtherFoo>().Count()); }
I don't use composites all that much, but it is an elegant approach.
Conditions
You can almost classify this as an extension of the composite pattern, by allowing to compose conditions. This is really useful when you have to build complex conditions are runtime.
[Fact] public void True() { IMessage<Null, bool> lhs = new Message<Null, bool>(notUsed => true); IMessage<Null, bool> rhs = new Message<Null, bool>(notUsed => true); var andMessage = lhs.And(rhs); Assert.True(andMessage.Send()); }
However, did you note the IMessage? I will get to that in a bit, and we will discuss this, it is an important part of Umbrella, but not one I like.
Containers
Couldn't figure out what this is supposed to do. Seems to be relation to the service locator impl.
Contracts
Couldn't figure out what this is supposed to do. Seems to be relation to the service locator impl.
Conversions
There are some nice things there, mostly accessible via Conversion().To<TTarget>(), handling Enums is nice:
[Fact] public void StringFromEnum() { Assert.Equal("Cancelled", Status.Cancelled.Conversion().To<string>()); Assert.Equal("VER", Status.Verified.Conversion().To<string>()); } public enum Status { [Description("VER")] Verified, Cancelled }
Or standard type conversions:
[Fact] public void CanConvertInt32ToString() { Assert.Equal("1", 1.Conversion().To<string>()); } [Fact] public void CanConvertStringToInt32() { Assert.Equal(1, "1".Conversion().To<int>()); }
Decorator
Again, the building blocks for the decorator pattern. This time, I don't see much use of this, since it doesn't seem to provide much value.
Equality
Provide a set of extension methods that extend equality comparisons. Mostly over enumerables and the like, from a brief look.
Events
There are the expected Raise() set of extension methods, but I find Observe and Notify far more interesting:
using(order.Observe(UpdateForm))
{
form.Show();
}
And:
public int Value { get { return value; } set { this.value = value; this.Notify(PropertyChanged, item => item.Value); } }
During the using statement, all NotifyPropertyChanged events will be captured. This is nice. The Notify() will handle property notifications without using strings. I don't deal much with INotifyPropertyChanged, however, so I care little for this.
There is also an implementation of observable, which may be useful. Again, this is not something I tend to use.
Expressions
Linq expressions are immutable, which make it a harder to build them. Umbrella solve this by giving us editable expressions, which are builders on top of normal extensions. Nice.
ExtensionsThis is a very loaded term in a utility project, and it contains a lot of things. Some of the things I liked are date handling:
[Fact] public void Equal() { DateTime x = new DateTime(2008, 2, 1); DateTime y = new DateTime(2008, 2, 2); Assert.True(x.Equal(y, DateTimeUnit.ToMonth)); Assert.False(x.Equal(y, DateTimeUnit.ToDay)); } [Fact] public void Truncate() { Assert.Equal(new DateTime(2008, 2, 1), new DateTime(2008, 2, 2).Truncate(DateTimeUnit.ToMonth)); }
There are a lot of things around date, but I think that this is a representative method:
public static DateTime BeginningOfWeek(this DateTime self) { return (self - self.DayOfWeek.DaysSince(Extensions.WeekBeginsOn).Days()) .BeginningOfDay(); }
There are also the standard (by now), "foo".IsNullOrEmpty() and "foo".HasValue(), additions to
I can't figure out the concept of Extension Points, however. Or, to be rather exact, I can't see what value it brings to the table.
What is really sweet is the handling of bit manipulation:
[Fact] public void Enum_Add() { BindingFlags flags = BindingFlags.Public; flags = flags.Add(BindingFlags.NonPublic); Assert.Equal(BindingFlags.Public | BindingFlags.NonPublic, flags); } [Fact] public void Enum_Remove() { BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic; flags = flags.Substract(BindingFlags.NonPublic); Assert.Equal(BindingFlags.Public, flags); }
And the correspond read approach:
[Fact] public void Enum_ContainsAll() { BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic; Assert.True(flags.ContainsAll(BindingFlags.Public)); Assert.True(flags.ContainsAll(BindingFlags.NonPublic)); Assert.True(flags.ContainsAll(BindingFlags.Public | BindingFlags.NonPublic)); Assert.False(flags.ContainsAll(BindingFlags.Public | BindingFlags.Instance)); Assert.False(flags.ContainsAll(BindingFlags.Instance)); } [Fact] public void Enum_ContainsAny() { BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic; Assert.True(flags.ContainsAny(BindingFlags.Public)); Assert.True(flags.ContainsAny(BindingFlags.NonPublic)); Assert.True(flags.ContainsAny(BindingFlags.Public | BindingFlags.NonPublic)); Assert.True(flags.ContainsAny(BindingFlags.Public | BindingFlags.Instance)); Assert.False(flags.ContainsAny(BindingFlags.Instance)); }
Factories
Seems to be relation to the service locator impl.
Locator
This is the service locator impl, I am ignoring that.
Messages
Messages are pretty important in Umbrella. They are defined as:
public interface IMessage<TRequest, TResponse> { TResponse Send(TRequest request); }
I strongly disagree with the term message here, however. A message in inanimate object, it doesn't act on its own. Messages in Umbrella are actions. In fact, the default implementation of a message is around a Func<TRequest, TResponse>.
Once you have those messages, however, you can start dealing with them in interesting ways. As a simple example, you can create a DisposableMessage, which will wrap another message and call Send() on it. Or bind the output of one message to the input of another, or simply chain them all together. A lot of the actions inside Umbrella are happening using those messages.
Reflection
This is a probably my favorite part in Umbrella. It abstract away all the gory reflection details:
[Fact] public void Instance() { Foo foo = new Foo(); IReflectionExtensionPoint fooReflection = foo.Reflection(); Assert.Equal(foo.I, fooReflection.Get("i")); fooReflection.Set("i", 2); Assert.Equal(2, foo.I); Assert.Equal(2, fooReflection.Get("I")); fooReflection.Set("I", 3); Assert.Equal(3, foo.I); Assert.Equal(3, fooReflection.Get("GetI")); fooReflection.Set("SetI", 4); Assert.Equal(4, foo.I); }
Leaving aside how much easier it make it to write the code, it also means that I now have an extension point to replace how it works if I need to. Nice.
Security
This appears to be based on contracts, which I already stated that I don't understand.
Serialization
This is cool, and I think that I figured out what extension point is for. Take a look at the code:
int instance = 1; instance.Serialization().Binary(new MemoryStream()); instance.Serialization().Xml(new MemoryStream());
This is a general pattern of usage in the code, you have an extension method that return an ExtensionPoint<T>, on top of which you can add additional extension methods, and build up a nice API in this fashion. It also make this big library much more discoverable.
Sources
A way to get values, not sure what it is for, however.
Threading
This give us a way to handle locking in a really nice fashion, as we have already seen with SyncronizedDictionary. Just create a SynchronizableLock<T> and start calling Lock.Read(lambda) and Lock.Write(lambda).
I really like this.
Validation
This is bare bone at the moment, but it is looking really nice. Check this out:
[Fact] public void String_NotNullOrEmpty_WithNull() { string value = null; var ex = Assert.Throws<ArgumentNullException>(() => value.Validation().NotNullOrEmpty("value")); Assert.Equal("value", ex.ParamName); }
Values
Again, this is making heavy use of messages and and I am pretty sure that I don't understand the intended usage. Digging through the code I found some interesting ideas about registering for disposal, which looks interesting. Basically, you can do the following inside classes that inherit from container:
Disposable.Add(new MyLock());
And it will be disposed when the container is disposed. Nice.
Web
Contains implementations of sources on session and web principals. I don't get sources, so I am not sure what I can make of this.
Summary
This has been a brief overview, but no means have I gone through the whole thing. Umbrella is big. At first, extension points are very strange, but they make sense once you realize how Umbrella is architected. They allow to extend a type and preserve the original value nicely.
There are some things that I really like, (Reflection, SyncronizedDictionary, Lock.Write) and some I can't figure out (sources, values, etc). I strongly suggest reading through the code, if only to get some ideas about patterns that are useful for C# 3.0.
Comments
I might be way off here since I havent looked at the code.
but:
That sample you posted looks very much like _currying_.
supplying one or more arguments to a function that returns a function untill the entire argument list have been passed.
And the last function returns the same result as you would have gotten if you passed all the arguments at once.
Memoization is something completely different AFAIK.
@Roger Yep, Memoization is simply caching function results based on arguments. What is being shown is currying, since you are taking a method of multiple arguments and turning it into a series of single argument methods.
If he were to pass more than one argument to any of the resulting methods then it would be considered "partial application" instead of currying. Currying specifically deals with single parameter methods.
Roger,
thanks, fixed.
Ayende,
What a great review! I'll make sure to delve into the details of your questions in more details as soon as I have some free time. If YOU're not understanding some of the code, I better find a way to make it simpler as not many will be able ;)
Documentation is on the way. It's always like that. You launch a project, then start a new client mandate and end up not having much time for documentation efforts.
But for what it's worth:
Sources: Think of it as something implementing IGetSet. It is a placeholder for a reference (just as WeakReference is). It can be Weak, Lazy, ThreadLocal. It can come from AppSettings, From an existing reference, ...
public interface ISource<T>
{
T Value { get; set; }
}
So instead of having to deal with Thread Local Data Slot, you just new up a ThreadLocalSource<T> and you got thread local variables.
Same thing with LazySource.
instead of having a property getter like:
public class Foo
{
private Bar bar;
public Bar Bar
{
}
}
you can have:
public class Foo
{
private ISource<Bar> bar = new LazySource<Bar>(Factory.CreateBar);
public Bar Bar
{
}
}
Values are exactly the same thing as Sources, except they expose IMessage Get and Set properties. This allows binding between 2 values as you're able to observe when the value has changed.
Francois,
Thanks for respond so quickly.
That explain why I was at a loss to get them, I have a drastically different way of solving those
Meaning?
virtual methods and proxies?
Take a look here:
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-commons/Rhino.Commons.Clr/LocalDataImpl/LocalData.cs
Cool.
ThreadLocalSource uses a ThreadStatic dictionary as well.
And HttpContextSource (not sure it's checked in yet) relies on HttpContext just as yours.
I would then use a SourceChain or something to chain them together.
My point was that there are other implementations (Lazy, WeakReference, ...) of ISource and that's why I tried to abstract an interface for all of those.
Thanks Ayende for the in-depth review. Some of the features sound really cool (especially because of them being simple yet useful). I'll definitively have a look at Umbrella.
Regards,
Andre
"Linq expressions are immutable, which make it a harder to build them. Umbrella solve this by giving us editable expressions, which are builders on top of normal extensions. Nice."
I think this is a step in the wrong direction. Linq expressions are immutable for a reason: you can process them in parallel, as immutable objects don't have threading issues. Another, more theoretical reason is that a function returns a value, which is either the same value it received, or a new one.
Mutable expression classes seem like the thing you want almost immediately when you start with linq expressions, as sooner or later you have to change something in an expression but as they're immutable, you've to make a copy, a new instance, which of course is a pain if you have references to that expression instance you want to mutate.
The thing is though: if you run into such a situation, it's a signal the code handling the expressions isn't good. As the appropriate way to handle expression objects/trees is to traverse them, and replace the subtrees you recognize with another expression, effectively a tree reduction system. In such a system, if done properly, you never run into a situation where you need to alter an existing instance, you can always simply create a new one with the value changed, replacing the original.
In practise it's very hard to achieve such a system with Linq expression trees however, due to the fact it uses parameters to refer to subtrees elsewhere in the expression tree. This means you need to make clones of these subtrees replacing the parameters, OR, you have to keep track of already handled subtrees. Nevertheless, my experience is that opting for mutable expression objects is not really what you want, as it leads to more errors. I know because my own expression objects were mutable at first and you run into bugs which are hard to track down.
Interesting. I never heard about the Umbrella project before. I just had a look at the code (poorly documented by the way) and it seems to me that some portions would well deserve to be part of the next version of the class library; in particular the extension methods for the generic collections and the enumerable interfaces, which I find especially useful.
@Frans: They aren't mutable expression trees per se. It's more of an Expression Tree Builder.
@Yann: It's not YET documented. It is on the way. We were challenged to get something out asap so we can get some valuable insight and feedback on what community liked about it.
Hi,
thanks for the review!
I agree with you, Ayende, that IMessage is a missleading name.
For ISources i have an implementation for ThreadLocal here:
http://startbigthinksmall.wordpress.com/2008/04/24/nice-free-and-reusable-net-ambient-context-pattern-implementation/
For personal use i also abstracted Session, Application and HttpContext.Items in a comparable manner.
I would love a post from Francois explaining all the different blocks and his approaches in the same style as you did.
Comment preview