But With C#, Who Needs Prism?
bitwise: People who program .NET in Visual Studio largely do so using C#. Given the fact that C# is by far the most widely used .NET language, why would anyone want to use Pascal instead?
mh: I think there are two big reasons why people would choose Prism over C#:
The first reason would be that they prefer the Pascal language, and its well-readable design over C-based languages. For me personally, that’s a big factor. I’m pretty fluent in C#, of course, and we use it for some of our projects (mostly for legacy reasons), but given the choice, I just find it more comfortable to write and work with Object Pascal code. It’s more readable, it’s less ambiguous (although, granted, C# is a big step forward on that front from C and C++), and I like its structure.
I realize that’s the sort of thing that people either will care about or won’t, but is not going to make a vast number of C# users who don’t come from a Delphi/Pascal background switch.
The second, and, in my opinion, more important reason, are language features. First, it’s important to realize that feature wise, Prism is a complete superset of C#. There’s literally not a single thing you can do in C# that you cannot do just as well in Prism. So you’re not giving anything up - that’s important. But then, Prism adds a whole slew of new features on top which make it a joy to work with.
For example, just recently introduced in Oxygene, there are "future" types, "async" blocks and expressions and "parallel" loops;
these make it really easy to write applications that scale out to systems with many CPUs or cores. This is something that will get tremendously important in the near future, as CPU speeds no longer increase, but instead systems get more (and sometimes slower) CPUs.
Microsoft is adding infrastructure to leverage this in .NET 4.0, called the "Parallel Framework", or "PFX". The PFX is really just a bunch of classes and functions you can call, but for Prism we went the extra mile to integrate these concepts into the language. So for example, you can now declare a variable to be of a "future" type - which means it will behave very much like a normal variable of a given type, except for one thing: it’s value will be calculated at some point in the future, possibly on a different thread.
So you can write, for instance:
method BinaryTreeNode.Sum: Int32;
Code:
1 2 3 4 5 6
|
begin
var leftSum: future Int32 := async Left.Sum();
var rightSum: Int32 := Right.Sum();
result := Value+leftSum+rightSum;
end; |
What we’re doing here is calculating the sum of a binary tree, by basically calculating the left and right side, and then adding everything together. But rather then first calculating Left and waiting for that to return, we do that asynchronously. As a result, leftSum is not a plain Int32, but a future Int32 - meaning a variable that, at some point in the future, will contain the result of our calculation. The hope is that - given enough CPU cores - this value will be calculated by some other thread, while we’re busy calculating rightSum.
The important part is the last statement. As you can see, we’re using leftSum as part of a longer expression here. The takeaway point is that, even though it’s a future, you can work with leftSum as if it were a plain integer. You can do math on it, you could call it’s member methods, etc. The compiler and the runtime will of course take care that at the time you need the value of leftSum, it will be calculated.
This stuff is going to make it really easy to write multi-threaded code, without having to think about manually creating threads, synchronizing them, getting data back, and all that. At the same time, the compiler and the runtime make sure that the code scales well, so as things get more complicated it will not go and spawn off a thousand threads that just waste resources - while at the same time if your application is running on a 8, 16 or 64-core system, a few years down the road, it will seamlessly be able to leverage all of those cores.
I apologize for going into so much detail on this particular, but I think it provides a great example of how proper language support for a concept can really drive productivity. And futures are just one of many language features that set Prism apart from C#. We have the Class Contracts I mentioned earlier. We have support for nullable types that goes way beyond what you can do in C# - like futures, nullable types in Prism work seamlessly as if they were plain value types - you can use them in expressions (which then turn nullable themselves) and call their members. And you can use the Colon : operator to access nullable types (and reference types), in a nil-safe fashion.
Also, many standard language features that do exist in C# have subtle improvements in Prism. For example, when implementing iterators, you can "yield" off an entire sub-sequence in a single call; for..each loops allow you to access the index of the current iteration or to filter down to only running the loop for members of a given type (think looping a list of all Controls on your form, and performing an action for Buttons only).
So I think we have a pretty good story for language benefits. For people coming from Delphi/Win32 or even Delphi.NET, there will be a sheer breathtaking range of new things they can now do, on the language level. But even for seasoned C# and VB developers, who already are accustomed to all the benefits of the .NET framework itself, there should be a lot to like in Prism.
And we’re not even touching on non-language features here, such as our exhaustive support for building apps for Mac OS X or Linux, using Mono.