Monday, January 21, 2008
Last time, I demonstrated the basics of tuple types in the F# language. However, I (intentionally) failed to answer a couple of important questions about tuples:
  1. Once values are bound together in a tuple, how can they be retrieved?
  2. How are tuples useful?

I'll leave the second question for next time. Today, we'll see how the values of a tuple can be extracted.

Here is the tuple that we began with last time:

> let pair = 37, 5;;

val pair = int * int

> pair;;

val it : int * int = (37, 5)

Extracting the values from this tuple is a simple matter of using the fst and snd functions (which F# held over from its ML heritage). These functions retrieve the first and second values, respectively, from a two-value tuple.

> fst pair;;

val it : int = 37

> snd pair;;

val it : int = 5

The results of these functions also can be assigned to variables.

> let x = fst pair;;

val x : int

> let y = snd pair;;

val y : int

> printfn "x = %d, y = %d" x y;;
x = 37, y = 5
val it : unit = ()

That's great, but what if we need to extract the values from a tuple whose length is greater than two?

> let triple = 2, 11, 29;;

val triple : int * int * int

Is there a thrd function we can use to get the last element out of the tuple above? Nope. In fact, the fst and snd functions that we used on pair won't even work with this tuple. The problem is that those functions are intended to be used only with tuples of two values. This becomes clear when their definitions are considered:

let fst (a,b) = a
let snd (a,b) = b

If we try to use either fst or snd with our triple tuple, a type mismatch error occurs.

> fst triple;;

  fst triple;;
  ----^^^^^^^

stdin(27,4): error: FS0001: Type mismatch. Expecting a
        'a * 'b
but given a
        int * int * int.
The tuples have different lengths
stopped due to error

Fortunately, F# provides a very natural syntax to extract the values from any tuple. The idea is to use a simple let statement. However, instead of binding to a single name, we bind to a pattern made up of several names. For example, we can extract the values from our triple tuple like so:

> let x, y, z = triple;;

val x : int
val y : int
val z : int

> printfn "x = %d, y = %d, z = %d" x y z;;
x = 2, y = 11, z = 29
val it : unit = ()

The obvious follow-up question is, what if we only want to retrieve one or two values from triple? Put another way, is it really necessary to bind each value of a tuple to a name even when we aren't interested in all of the values? The answer is, no, it isn't necessary to bind each value of a tuple of a name. F# provides an ultra-handy wildcard pattern that trivializes this problem. Wildcards allow us to bind only the information that we're interested in by adding "holes" to a pattern. In code, they are represented by an underscore (_) character.

> let x, _, z = triple;;

val x : int
val z : int

> printfn "x = %d, z = %d" x z;;
x = 2, z = 11
val it : unit = ()

Very cool. We'll see more uses of wildcards as this series progresses.

That should answer the first question above. Next time, we'll explore some important uses of tuples that make them very compelling—especially for .NET developers.

posted on Monday, January 21, 2008 7:41:25 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
 Friday, January 18, 2008
A few months ago, I wrote about how there had been a big price break in the Ultimate Developer Rig presented by Jeff Atwood and Scott Hanselman. About a month later, I went ahead and built my own version of this glorious box.

Since the price had fallen so low ($1,503.88), I decided to increase the amount of ram from 4GB to 8GB. This was due in part to a conversation that I had with my good friend and DevExpress colleague, Oliver Sturm. We were discussing the well-known limits of ram in 32-bit Windows. Oliver made the point, "I'd rather have 4GB on 32-bit Windows than 4GB on 64-bit Windows." The thinking is that, while 32-bit Windows may not be able to fully access 4GB of ram, 4GB on a 64-bit machine might seem cramped since applications use more memory due to wider pointers. Besides, ram is cheap! There's no reason not to purchase a little more elbow room—especially since the price of the machine had already dropped by $400.

The final build that I settled on is below:

Component Price Paid Current
Antec P182 Gun Metal Black 0.8mm cold rolled steel ATX Mid Tower Computer Case - Retail $149.99 $139.99
MSI P6N SLI Platinum LGA 775 NVIDIA nForce 650i SLI ATX Intel Motherboard - Retail $139.99 $139.99
MSI NX8600GTS-T2D256E-OC GeForce 8600GTS 256MB 128-bit GDDR3 PCI Express x16 HDCP Ready SLI Supported Video Card - Retail (2) $299.98 $279.98
Western Digital Raptor WD1500ADFD 150GB 10,000 RPM Serial ATA150 Hard Drive - OEM $179.99 $169.99
Western Digital Caviar RE WD3200YS 320GB 7200 RPM SATA 3.0Gb/s Hard Drive - OEM $89.99 $89.99
Intel Core 2 Quad Q6600 Kentsfield 2.4GHz LGA 775 Quad-Core Processor Model HH80562PH0568M - OEM $260.00 $260.00
ZALMAN CNPS9500 AT 2 Ball CPU Cooling Fan/Heatsink - Retail $47.99 $44.99
CORSAIR CMPSU-520HX ATX12V v2.2 and EPS12V 2.91 520W Power Supply - Retail $124.99 $124.99
OCZ Gold 4GB(2 x 2GB) 240-Pin DDR2 SDRAM DDR2 800 (PC2 6400) Dual Channel Kit Desktop Memory Model OCZ2G8004GK - Retail (2) $319.98 $207.98
LITE-ON 20X DVD±R DVD Burner with 12X DVD-RAM write and LightScribe Technology Black E-IDE/ATAPI Model LH-20A1H-185 - OEM $28.99 $30.99
  $1,641.89 $1,488.89

As you can see, the price has dropped even further, and the cost of 8GB of ram is now around $200!

Full Disclosure: I had a negative experience with the MSI P6N SLI Platinum motherboard. It was dead on arrival. After installing the CPU, RAM and a video card, the motherboard refused to POST. Newegg's RMA service did a fantastic job of replacing the board. However, there's nothing worse than removing a CPU, cleaning off the thermal paste and hoping that it works the next time it's installed. Fortunately, the second motherboard worked fine and has been running well for nearly two months.

The time I've spent developing with this machine have been nothing short of pure joy. Builds are faster, multiple VMs don't drag me down, virus scans occur without my knowledge... it's complete bliss. I can even watch every episode of Buffy the Vampire Slayer, season 1 simultaneously without a hiccup.

Quad core in action

Quad core in action

I should also mention that my trophy wife, while OK with the initial purchase, is grumbling a bit after seeing the current component prices. ;-)

posted on Friday, January 18, 2008 12:42:44 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
Another feature of the F# language that I crave desperately when writing C# or VB code is F#'s built-in support for tuples. What's a tuple? Simply put, a tuple is an ordered group of values. In one sense, a tuple is very similar to the anonymous types of C# 3.0. The chief difference is that the values in an F# tuple are not named like the properties of a C# anonymous type.
NeRd Note
Most pressing on your mind is likely the question of how one pronounces the word, "tuple." Well, my British friends emphatically point out that it's "too-pull," while my red-blooded, English-language-abusing American friends1 like to say "tuh-pull."2 However, when my British friends speak, they always sound intelligent. I think it has something to do with the accent. So, I'm going with "too-pull." I like to sound smart—especially when it's easy.

In F#, a tuple3 is concisely declared as a let statement with a single name and multiple values separated by commas.

> let pair = 37, 5;;

val pair = int * int

> pair;;

val it : int * int = (37, 5)

Notice that F# infers the type of pair to be int * int. The asterisk (*) doesn't actually mean multiplication in this case. Instead, it indicates that the two types on either side are bound together as one type.

Tuples can contain any number of values, and the values don't have to be of the same type.

> let triple = 0, "F# Rules!", 12.8;;

val triple : int * string * float

Tuples can be compared for equality.

> pair = (29, 13);;

val it : bool = false

> pair = (37, 5);;

val it : bool = true

> pair = (19, 23);;

val it : bool = false

And other comparisons are also legal.

> (1, 1) < (1, 2);;

val it : bool = true

> (2, 1) > (1, 2);;

val it : bool = true

However, tuples with different types cannot be compared. Trying to compare pair, which is of type int * int, with a tuple of type int * string results in an error:

> pair = (0, "F# Rules!");;

  pair = (0, "F# Rules!");;
  -----------^^^^^^^^^^^^

stdin(12,11): error: FS0001: This expression has type
        string
but is here used with type
        int
stopped due to error

In addition, tuples of different lengths cannot be compared.

> triple = (0, "F# Rules!");;

  triple = (0, "F# Rules!");;
  ----------^^^^^^^^^^^^^^^

stdin(13,10): error: FS0001: Type mismatch. Expecting a
        int * string * float
but given a
        'a * 'b.
The tuples have different lengths
stopped due to error

Interestingly, in the above code, the F# compiler doesn't bother inferring the types in the tuple, (0, "F# Rules!"). It is left generic: 'a * 'b. The F# compiler sees that the tuples have a different number of values and stops.

Next time we'll look at some cool ways to use tuples in F# programming.

1Please don't hurt me Keith!
2Usually while sucking down a can of Schlitz.
3too-pull

posted on Friday, January 18, 2008 10:14:39 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]

kick it on DotNetKicks.com
 Wednesday, January 16, 2008
I'm continuing my series showing ways in which F# is a exciting .NET language. As I mentioned before, if you have any suggestions for future topics please feel free to email them to dustin AT diditwith.net.

While F# can easily access the standard .NET formatting functions (e.g. String.Format()), it also provides its own set of functions for outputting formatted text. In fact, F# offers the a printf-based family of functions that should be familiar to C programmers. Consider the following simple example using F#'s interactive environment.

> printf "%s %d 0x%x %.2f\n" "F# Rules!" 128 128 12.8;;

F# Rules! 128 0x80 12.80

Most of these formatting functions also have an additional "n" version that implicitly adds a new-line character. For example, we could modify the above code to use printfn like so:

> printfn "%s %d 0x%x %.2f" "F# Rules!" 128 128 12.8;;

F# Rules! 128 0x80 12.80

Of course, using an invalid argument will result in an error. Notice what happens if we pass 12 instead of 12.8 for the %f format specifier:

> printfn "%s %d 0x%x %.2f" "F# Rules!" 128 128 12;;

  printfn "%s %d 0x%x %.2f" "F# Rules!" 128 128 12;;
  ----------------------------------------------^^^

stdin(3,46): error: FS0001: The type 'int' is not compatible with any of the
types float,float32, arising from the use of a printf-style format string
stopped due to error

What should give .NET developers pause is the fact that the error above does not occur at runtime. This isn't some exception being thrown—it's a compiler error. In other words, the compiler actually parses and type-checks format strings!

This behavior becomes more useful inside of Visual Studio. When a type mismatch occurs within a format string, the F# background compiler marks the problem with a red squiggly underline:

Type-safe Format String Error

Hovering the mouse over the error will show a tooltip containing the same message that the interactive environment displayed.

Type-safe Format String Error with Tooltip

This is another example of how F# is extremely statically-typed. The F# compiler works to make even format strings type-safe.

posted on Wednesday, January 16, 2008 8:12:50 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]

kick it on DotNetKicks.com
 Tuesday, January 15, 2008
I'm starting a brand new series of short articles about F#. The plan is to describe features that, for me, make F# a compelling and enjoyable .NET language. So far, I have 10-15 articles in mind, but I'm open to suggestions. If you have any ideas for additional topics, please email them to dustin AT diditwith.net.

The Interactive Environment

Like Python, Ruby and many other programming languages, F# provides an interactive scripting environment. However, F# is different in that the interactive environment is not an interpreter. Instead, it dynamically compiles code on-the-fly.

There are two ways to load this environment:

  • Run fsi.exe from the bin subdirectory of the F# distribution.
  • Load the F# Interactive for Visual Studio add-in from the Visual Studio Add-in Manager.

Once the environment is loaded, a splash screen is displayed. (NOTE: the examples here use fsi.exe.)

MSR F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.3.7, compiling for .NET Framework Version v2.0.50727

NOTE:
NOTE: See 'fsi --help' for flags
NOTE:
NOTE: Commands: #r <string>;;    reference (dynamically load) the given DLL.
NOTE:           #I <string>;;    add the given search path for referenced DLLs.

NOTE:           #use <string>;;  accept input from the given file.
NOTE:           #load <string> ...<string>;;
NOTE:                            load the given file(s) as a compilation unit.
NOTE:           #time;;          toggle timing on/off.
NOTE:           #types;;         toggle display of types on/off.
NOTE:           #quit;;          exit.
NOTE:
NOTE: Visit the F# website at http://research.microsoft.com/fsharp.
NOTE: Bug reports to fsbugs@microsoft.com. Enjoy!

>

At this point, it's easy to start typing F# code. To execute code, type a double semi-colon. The following bit of code, when typed into the interactive environment, will instantiate and display a new .NET Windows Form:

> open System.Drawing
- open System.Windows.Forms;;

> let myForm = new Form(Text = "Hello, World!", Visible = true);;

val myForm : Form

The first two lines open the System.Drawing and System.Windows.Forms namespaces. This is analogous to C#'s using and VB's Imports statements. It isn't necessary to reference the System.Drawing.dll or System.Windows.Forms.dll assemblies because they are implicitly referenced by the environment.

The third line instantiates a new Form, sets its Text and Visible properties, and binds it to the name myForm. Because the code is dynamically compiled and executed, the form is displayed immediately.

Hello, World! Form

Now that the form is instantiated, it can be manipulated at runtime.

> myForm.BackColor <- Color.Blue;;
val it : unit = ()

When executed, the above code changes the form like so:

Hello, World! Form (colored)

The F# Interactive Environment is a great way to break out of the standard edit-compile-debug rut and prototype some code. It can even output to a .NET assembly. Run "fsi.exe --help" to see more ways in which the interactive environment can be used.

posted on Tuesday, January 15, 2008 8:06:10 AM (Pacific Standard Time, UTC-08:00)  #    Comments [6]

kick it on DotNetKicks.com
While at CodeMash, I sat down with my good friend Chris Woodruff for a casual podcast interview discussing life, code, being a Microsoft MVP, DevExpress and the CodeMash conference.

CodeMash 2008 Interview with Dustin Campbell

NOTE: This interview is not technical and gets a little off-topic at the end.

In addition, there are several other CodeMash interviews, including:

posted on Tuesday, January 15, 2008 6:10:19 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]

kick it on DotNetKicks.com
 Monday, January 14, 2008
While at CodeMash, I had the opportunity to sit down with Scott Hanselman and record an episode for his renowned podcast, Hanselminutes. As a follower of the podcast, I was thoroughly flattered to be included among his guest list. The show turned out well, but the experience was definitely nerve-wracking. Here are some tips in case you ever end up in the hot seat across from Scott:
  1. Learn to hold and speak into a microphone. This is critical. During the recording, I kept drifting from the mic, which required editing in post-production.
  2. Be prepared to be disarmed by the interviewer's eloquence. Scott is a very well-spoken guy with a lot of experience. Don't be surprised when he pulls the perfect metaphor out of thin air.
  3. Be aware of your medium. When recording audio, be careful using words to explain a concept that might be better expressed with a visual diagram. Remember: it's a warning sign if you start "talking with your hands."

Scott and I talked about some of the features that make F# such an exciting language. We tried to keep it short on academia so that it would be appealing to any developer. The idea was to start small with some bite-sized concepts. Check it out!

Starting Small with F# with Dustin Campbell

posted on Monday, January 14, 2008 8:16:29 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]

kick it on DotNetKicks.com
 Wednesday, January 02, 2008
I guess I've been a little busy lately because I completely missed the release of Ultramon™ 3.0.1 Beta 2 back on December 15th. Ultramon is simply the best management tool for multiple monitors available. I would not survive for long in front of my monitor setup without it.

This release has some welcome changes and bug fixes for Windows Vista. The full release notes are here.

posted on Wednesday, January 02, 2008 1:52:50 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]

kick it on DotNetKicks.com
Today, while making some changes to my Plaxo Pulse profile, I was presented with the following error message:

Plaxo Error

Coffee immediately shot out of my nose.

Once I regained control of myself (and after taking the screenshot above), I clicked the X, and the message went away. I never did find out what that error actually was.

posted on Wednesday, January 02, 2008 1:13:00 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]

kick it on DotNetKicks.com
 Tuesday, January 01, 2008
It's a new year! Time to return to my passion: torturing programming languages and making them cry like little children.

This article has bit of everything: Scheme, C# and VB lambda expressions, closures, lambda calculus... the works. By the end, you'll either be enlightened or stark, raving mad.

Happy New Year!

posted on Tuesday, January 01, 2008 1:33:25 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
 Monday, December 31, 2007

Mug

Hello again, X-mas celebrants! I have just one last verse in my carol to make all of your Visual Studio 2008 experiences bright. Don't let your hearts be saddened because my song is drawing to a close. After today, a new year filled with its own code blessings will be upon us.

My last offering is a simple one—a stocking stuffer, really. It's one last refactoring targeted at Visual Basic developers.

And so, it is with a heavy heart that I begin the last verse of the "Twelve Days of Refactor! X-mas..."

"On the twelfth day of X-mas my true love (DevExpress) gave to me..."

Extract XML Literal to Resource

In my opinion, the most compelling new feature of Visual Basic 9 is XML Literals. We've already seen how Refactor! Pro can be used to manipulate XML Literals to great effect, saving literally hundreds of keystrokes. However, sometimes we don't want to dynamically build XML. Sometimes we simply want to consume a chunk of raw XML.

Module TwelveDaysOfXmas
  Sub Main()
    Dim lBook = <book isbn="12252007">
                 <title>Refactoring: The True Meaning of X-mas</title>
                 <price>$0.00</price>
                 <author>
                   <first-name>Dustin</first-name>
                   <last-name>Campbell</last-name>
                 </author>
               </book>
  End Sub
End Module

If we're not adding embedded expressions to the above XML literal, it really belongs in a resource file. However, moving that XML to a resource is a terrible inconvenience. Thankfully, Refactor! Pro provides the Extract XML Literal to Resource refactoring. When applied to the code above, Extract XML Literal to Resource produces the following:

Module TwelveDaysOfXmas
  Sub Main()
    Dim lBook = XElement.Parse(My.Resources.XMLFile)
  End Sub
End Module

When compared to the acrobatics we've already seen Refactor! Pro perform on XML Literals, this refactoring might seem like a very small thing. It may be simple, but it's incredibly helpful when you need it. The first time that you attempt to move an XML Literal to a resource for translation purposes or any other reason, you'll be thankful that you have Extract XML Literal to Resource to do the job for you.

Check Out This Screencast to See Everything that Extract XML Literal to Resource Handles for You!

And so ends my song. We've taken a merry sleigh ride through many of the new language features available in Visual Studio 2008, and we've seen how Refactor! Pro can help you leverage those features today. It's been my distinct pleasure to be your guide on this journey.

Before I take my leave, I have one small piece of advice. If you've been waiting impatiently for the other tool to support for Visual Studio 2008, remember that Refactor! Pro has been there since the very first beta. No matter what that tool vendor may try to tell you, Visual Studio 2008 was not a surprise. Everyone had more than a year to prepare. The only ones taken by surprise were those who weren't paying attention.

And with that, I wish you a continued happy holiday season and hope Refactor! Pro can make your new year bright!

Happy New Year!

posted on Monday, December 31, 2007 10:57:09 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]

kick it on DotNetKicks.com