Allen Lee's profileAllen Lee's MagicPhotosBlog Tools Help

Allen Lee's Magic

There's no answer here except some worth trying ideas.
August 08

Windows Live Photo Doesn't Work!

I want to upload some photos to Windows Live, but it always prompts failure. How come?

August 05

From C# 3.0 to F#

From C# 3.0 to F#

 

Written by Allen Lee

 

First of All

      What was in your mind when you saw the title of this article? Let me guess: "What the hell is going on? I'm even in the progress of learning C#, and you are about to tell me F#? Are you trying to kill me?" Well, I remember that there's such suggestion in Pragmatic Programmer: "learn at least one new language every year." Recently, Gustavo Duarte posted an entry in his blog questioning this suggestion: "learning new programming languages is often a waste of time for professional programmers." What's your opinion? Some of you would say, "I don't think it's necessary to learn a new programming language unless I have the need." Then when would you have that need? Recall from your project experience and you would notice that the need usually came from your project rather than you. If your project has the need of an obsolete programming language, it might not be possible for you to make a rejection. According to Maslow's Hierarchy of Needs, you would not be interested in learning a new programming language if you had been awfully busy with your project. Perhaps the job of learning a new programming language could only go to language researchers, especially in today's fast growing society. So why do I want to learn a new programming language when I'm not (currently) a dedicated language researcher?

      I remember that there's an interesting law called "The Law of The Hammer" in Gerald M. Weinberg's The Secrets of Consulting: A Guide to Giving and Getting Advice Successfully:

The child who receives a hammer for Christmas will discover that everything needs pounding.

What were you thinking when you finished reading the sentence above? Perhaps you have got what I would like to say: Tools would bring their convenience to the users while reserve their constraints to the ways to solve the problems. Programming languages represent the ability of abstraction and expression of the problems, and different paradigms help programmers view the problems in different angles, which is the main reason for me to learn a new programming language. Then why do I choose F#? Well, that's all because of C# 3.0. You know, C# 3.0 introduces many functional programming concepts and features, and I was just curious about what a functional programming language looks like and later I met with F#. During the learning of F#, I found many similarities between C# 3.0 and F#, which results in the idea of writing this article.

 

Creating Types

      People usually try to understand new things with their existing background, in other words, your knowledge and experience will influence how you learn new things. If you are an object-oriented programmer, then the first question you want to ask will probably be: How to create types?

      F# supports Record Type which is similar to a class created with auto-implemented properties in C# 3.0:


Code 1

and initializing such a type in F# is very intuitive:


Code 2

The type of book is inferred to be Book based on the properties you used. Now, you may ask: "What if there are two different types both of which define the same properties?" Although it's not likely to happen with careful design of types, you can initialize it with explicit syntax when the trouble really comes:


Code 3

      Encapsulation is a technique of object-oriented programming which is used to hide and protect the internal state of an object. The internal state of an object usually changes during the lifetime of the object; however, when you try to modify the Price property in F# Interactive, an error will occur ("<-" is used for assignment, just as "=" in C#):


Figure 1

Why? Well, in F#, objects are immutable by default, just like .NET strings. Modifying the Price property can be thought of as creating a new object with the same values of Title, Authors and Tags properties of the original object and the new value of the Price property:


Code 4

      Now, you may think: it's not a good idea to consume the memory this way even though it's very cheap. In object-oriented programming, holding and maintaining internal state is very important to an object, which helps us accomplish many complex operations, but also brings the complexity and the cost of concurrency. It doesn't make sense to tell in general which of mutable approach and immutable approach is better, but for a given system, some objects are suitable to be designed as mutable, while others are better to be immutable, which keeps a balance between both sides.

      In C#, objects are mutable by default, but you can pin some data through the readonly keyword; while in F#, objects are immutable by default, but you can make some data modifiable through the mutable keyword. If I redefined the Book as follows:


Code 5

then the compiler would not complain when I modified the Price property. If you have decided to make an object mutable, then you should prepare well for concurrency. What? Your program only runs in a single thread on a single core platform? Then make your choice of mutability or immutability based on the toss of a coin!

      Besides Record Type, F# also supports Discriminated Union, Tuple and Constructed Class Type. Check out F# Home if you are interested in them.

 

Initializing Objects

      C# 3.0 introduces object initializer and collection initializer; F# also supports similar features. Suppose I'm going to initialize System.Windows.Forms.ListViewItem with its Text, Selected and ToolTipText properties set, I can do it this way:

 
Code 6

In F#, this feature is called Initial Property Settings (or Optional Property Settings). The code above is equivalent to the following:

 
Code 7

The code above tells the prerequisite of this feature: the property you want to initialize must contain a set accessor. Now, you may ask: "What if the constructor I want to call takes parameter(s)?" Well, it won't be a problem. Suppose the constructor you want to call takes a string as its parameter, you can do it this way:

 
Code 8

or this way:

 
Code 9

      In Code 8, I simply passed a string together with the properties to be initialized; while Code 9 uses F# Named Argument feature. Named arguments can be placed anywhere, even in between Selected and ToolTipText, but anonymous arguments must be placed in front of the properties to be initialized in order. Now, you may ask: "What if the parameter of the constructor to be called and the property to be initialized have the same name?" Hey, are you going to test F#'s patience? Well, in case it really happens, the following should be taken into account. First, in F#, the same name is not allowed to appear twice, no matter whether it belongs to a parameter or a property; therefore, the compiler will complain if it sees the same name twice. Second, in this case, parameters take higher priority than properties; therefore, a parameter will win the name if a property shares the same name.

      Now that you have learned how to initialize a single object, it's time to have a look at a collection of objects. In F#, Microsoft.FSharp.Collections.List<'a> is the collection type you will often encounter ("'a" is type variable). Suppose I want to initialize a collection of Book objects (see Code 1 for the definition of Book), and store them in an F# list, I can do it this way:

 
Code 10

Elements in the list are separated by ";". F# is able to infer the type of the list to be List<Book>. F# lists are often used within F# code, and if your code needs to interoperate with .NET class library or other languages, then arrays are preferred (Can you figure out the difference between Code 11 and Code 10, although they are very similar):

 
Code 11

      F# supports Range Expression for integer lists. You can specify the start value and the stop value as follows:

 
Figure 2

and even the step value:

 
Figure 3

      For more information on F# lists, please check out Dustin Campbell's Why I Love F#: Lists - The Basics and Chris Smith's Mastering F# Lists.

 

Logic Outsourcing

      Suppose you were going to sort books2 array (see Code 11 for the definition) with the Sort method I provided, but soon you realized that the method took only one parameter, then you would probably ask: "How could I tell the method that I want to sort the books based on their prices?" "I'm so sorry to say that it would not be possible because the method would choose the appropriate way for sorting on its own." Now, how do you like this answer?

      Today, people demand for customization and personalization, and will no longer be satisfied by standardized software without configurability and extensibility. So how can people participate in the game? Take the Sort method above for example, it might not be possible for me to find such an appropriate way to sort anything; therefore, I need the help for sorting from the users, which is the place for user participation. At this point, we match the need from the users and that from the programmers, which results in a win-win situation.

      Take a look at the overloads of System.Array.Sort method, you will notice that there are mainly two ways for logic outsourcing in .NET: delegate and interface. In F#, Lambda Expression can be used for logic injection for the overloads that accept delegate as parameter (compare function is used for general comparison in F#):

 
Code 12

Of course, named function can also be used for logic injection:

 
Code 13

Pay attention to the definition of comparePrice function. I didn't mention the types of the two arguments x and y, but F# had successfully inferred them to be Book from the function body and the context. Sweet!

      In F#, functions can also be defined through Lambda Expression; thus, comparePrice function in Code 13 can also be defined as follows:

 
Code 14

The comparePrice function in Code 14 is equivalent to that in Code 13, and the usage of them remains the same. We can also learn from Code 14 that functions in F# are actually values, and the Lambda Expression we used in Code 12 is just the value of the comparePrice function defined in Code 14.

      Lambda Expression provides a compact way for logic injection, but what if an interface rather than a delegate is expected? Then Object Expression will come into play:

 
Code 15

      Note that the wildcard operator "_" is used to request F# to infer the type variable of IComparer<'a>, which is then Book. Well done! F# Object Expression and C# 3.0 Anonymous Type are different in that F# Object Expression only allows you to implement the members of an interface or override the members of base type (no new members are allowed), and C# 3.0 Anonymous Type allows properties only.

 

Extending Types

      Suppose I want to add a collection of Book objects to ListView. What should I do? If you are used to thinking in imperative way, then you would first create a ToListViewItem function:

 
Code 16

then "foreach" those Book objects, apply ToListViewItem function to each Book object, and add the result of that function to ListView. Since ToListViewItem function is related to Book objects, you might also consider to define it within Book type as an instance member function:

 
Code 17

Note that the "b" in front of ToListViewItem member function refers to the current instance of Book object, which is similar to "this" keyword in C# and "Me" keyword in VB.NET. Since F# doesn't enforce such a keyword; therefore, you can use any symbol of your choice based on your needs, and of course you can also enforce the use of a specific keyword through a coding standard. Now, you can "foreach" those Book objects, call ToListViewItem member function on each Book object, and add the result of that function to ListView.

      At this point, there might be a question: "Book should have been a neutral data container, and now holds a strong relationship with Windows Forms framework just because of the use of ListViewItem within its definition, which brings damage to its purity." How do you like these words? In fact, we might want to keep a weak relationship between Book type and ToListViewItem function, which is disabled by default until activation. In this case, we can consider a separation of the ToListViewItem function to a different module through F# Type Extension (Suppose Book type is defined in Lib namespace):

 
Code 18

Now, if we do not open the Ext module, the relationship between Book type and ToListViewItem function will stay inactive:

 
Figure 4

and if the Ext module is open, the relationship will become active:

 
Figure 5

      Do you have the feeling that F# Type Extension is very similar to .NET Framework 3.5 Extension Method? Well, when Type Extension code and the related type are in different namespace, it will have the same effect as Extension Method, and is called Optional Extension; however, when they are in the same namespace, it will be equivalent to Partial Class, and is called Intrinsic Extension. Since the implementation of Optional Extension in IL is different from that of Extension Method, F# Optional Extension cannot be recognized in C# 3.0/VB.NET 9.0, nor can C# 3.0/VB.NET 9.0 Extension Method be recognized in F#. It might look weird that F# implements its own approach rather than directly uses .NET Framework 3.5 Extension Method. In fact, the current version of F# (1.9.4) is based on .NET Framework 2.0 rather than 3.5; therefore, it's not intended to have two different implementations simultaneously. I posted my question on whether F# Type Extension would be migrated to .NET Framework 3.5 Extension Method on hubFS.net, and Don Syme's reply was that they are planning to emit the ExtensionAttribute when it makes sense to do so.

      So what if I want to define Extension Methods that can be recognized by C# 3.0/VB.NET 9.0 in F# at this point of time? It won't be a problem, although F# doesn't recognize them:

 
Code 19

The syntax for defining Extension Methods in F# is similar to that in VB.NET 9.0 for they both use ExtensionAttribute explicitly. Then, compile your code as class library, and add reference to it within your C# 3.0/VB.NET 9.0 project. Now things are ready for you. Note that you must add reference to .NET Framework 3.5 libraries within your F# project before any operation above.

      Oops, I almost forgot the original goal! We've done so much, but ultimately we still need to "foreach" those Book objects, apply transformation to each Book object, and add the result to ListView. Is there any simpler approach in F# for this task? In fact, F# tends to accomplish this task through function composition:

 
Code 20

The line of code above shows the flow of data: the data flows from books2, though the composition of Array.map function and ToListViewItem function, and finally to listView.Items.AddRange method. It can be read as: transform each element of books2 array with ToListViewItem function, and send the result to listView.Items.AddRange method. We can also learn from the line of code above that ToListViewItem function we defined at the beginning is enough if we think of this task in functional way.

 

Querying Data

      There's no doubt that the most attractive feature in C# 3.0 is to query data with LINQ. As mentioned before, the current version of F# is based on .NET Framework 2.0, so how can I query data in F#? We know that IEnumerable<'a> is the core interface of LINQ, and also the prerequisite for any query operation. In F#, you can use seq<'a> or IEnumerable<'a>. seq<'a> is a Type Abbreviation of IEnumerable<'a>, which is similar to typedef in C++. The functions related to seq<'a> are included in the Microsoft.FSharp.Collections.Seq module, such as Seq.filter function, Seq.map function and Seq.orderBy function.

      Now suppose I want all the books (see Code 10 for definition) on F# (Tags property contains "F#") sorted based on the Price property. What should I do?

      To determine whether a book matches the condition, you can split its Tags property into a string array with ";", and then check to see if "F#" exists in the array. To split a string into a string array, you can use System.String.Split instance method. However, to determine whether a collection contains the specified element, the only way seems to be specifying your predicate through Lambda Expression. To make life easier, I define a contains function as follows (it plays the same role as System.Linq.Enumerable.Contains method):

 
Code 21

Seq.exists function was used inside contains function together with a Lambda Expression for equality determination. Note that contains function passed compilation even if I didn't specify the types of its arguments! Interesting? Then what are the types of value and source arguments? Well, when F# compiler sees contains function, it will notice that value and source arguments will be used as arguments of Seq.exists function; therefore, it will try to infer the types of value and source based on the signature of Seq.exists function. Since Seq.exists is a generic function, and we didn't specify any further constraint when defining contains function; therefore, it will infer contains function to be a generic function and value and source to be generic arguments. This process is called Automatic Generalization. Now, you might notice that the order of parameters of contains function is opposite to that of Enumerable.Contains. Looks weird? Well, making the collection as the first parameter of Enumerable.Contains method is just to satisfy the prerequisite of Extension Method; while making it the last parameter of contains function here is for cooperation with the pipeline operator "|>". If I want to determine whether coll collection contains elem element, I can do it this way: coll |> contains elem. If you are interested in learning more about the pipeline operator "|>", please check out Brian's Pipelining in F#.

      With the preparation above, we can now start to query the data:

 
Code 22

Seq.filter function, Seq.map function and Seq.orderBy function are equivalent to Enumerable.Where method, Enumerable.Select method and Enumerable.OrderBy method respectively. If we redefine Seq.filter function, Seq.map function and Seq.orderBy function to be where function, select function and orderby function respectively:

 
Code 23

then Code 22 could be rewritten as follows:

 
Code 24

Now come and have a look at the equivalent C# 3.0 code:

 
Code 25

Surprise! No? Very disappointed? Just because I wrote an unnecessary select? Oops …

      Here, you may ask: "What if I only want Title and Price properties?" This time, F# Tuple will come into play:

 
Code 26

Then, you may ask: "What if I want to extract all the book titles from q to a new collection?" Well, you can do so through select function, but I want to try F# Sequence Expression instead:

 
Code 27

We know that each element in q is actually a Tuple containing two piece of data, in other words, each element will match (a, b) pattern within which a will be assigned to a book title and b a book price. But because I only cared the book title, I used the wildcard operator "_" in place of b, telling that I didn't care the data in that place. Similarly, if I want to extract all the prices from q and calculate the sum of them, I can do it this way:

 
Code 28

      If you have ever read my C# 3.0 in My Eyes (written in Chinese), you will remember the initializer for dictionary. Does F# support similar syntax? Unfortunately, there's no such support at this point of time; however, creating a Map<'key, 'a> from a List<'a> in F# is pretty easy:

 
Code 29

The sentence above can be read as "transform books with fun b -> (b.Title, b), and send the result to Map.of_list function".

 

The Joy of Learning Languages

      Programming languages are friends in our daily life, but have you ever stopped to think what a programming language is in itself? Perhaps, programming languages are just tools for you to accomplish programming tasks; thus, there's no need for such thinking. However, things are different for me. One of my best friend once said, "I'm very fond of playing with stock market through which I'm able to see human nature." Similarly, I'm very fond of playing with programming languages through which I'm able to learn how the designers and the users think.

      When a new programming language comes out, some might announce that some old programming language would be replaced or even die; while others might question the necessity of the new programming language. No one wants to see the programming language of their choice becomes obsolete. The moment you choose a programming language, you actually accept its view of the world, and thus fight for your choice, which is why the arguments between programming languages can be so fierce. I remember there's a post on hubFS.net within which optionsScalper replied as follows:

I tend not to think of "vs." when doing this type of work.  F#, C#, C++ and others are nothing more than tools.  Used well, each is capable of yielding great results.

I think learning new programming language(s) should be a joy rather than a trouble. Do you think so?

December 05

Serializable + MarshalByRefObject

If you once did something with .NET Remoting, you must have heard of MBV and MBR. In a nutshell, you configure an object as MBR object by deriving it from MarshalByRefObject; while MBV by applying SerializableAttribute on it. What if you do these two to the same object? Let's say we have a RemoteCar class which has been done those two and a RemoteCarProvider which is configured as MBR and contains a GetCar method returning a RemoteCar as follows:
 
public RemoteCar GetCar()
{
    return new RemoteCar();
}
 
In order to know what's going on with RemoteCar, I add a Drive() method inside it:
 
public void Drive()
{
    Console.WriteLine("Driving...");
}
 
OK, run all things. You will notice the output of Drive() is in the server-side console, which means it is now MBR even though there's a SerializableAttribute applied.
 
November 17

Expression Design

        When Microsoft announced Expression Studio, I made up my mind to learn Expression Blend because it's native to WPF/XAML. Among those four products of Expression Studio, I thought Expression Design was less possible for me to use just because I didn't use that kind of tools. But nowadays, the one I use most frequently is Expression Design. I'll falling in love with it because it helps me achieve what I didn't even think I could do. Thanks to Expression Design, I can share my imagination with others in an intuitive and graphical way.

November 01

Amazon for Word 2007

      Have you ever thought of searching book within Word 2007? Here's my first attempt to do that (the article was written in Chinese): http://www.cnblogs.com/allenlooplee/archive/2007/11/01/945081.html. With that simple add-in, you can search book available in Amazon.com and add a hyperlink to the web page of the book.

 
Updated 8/10/2008