Tuesday, September 23, 2008

A thought on F#

A while ago I read this blogpost by Phil Wadler. The post is a comment on an article from an issue of Journal of Functional Programming. In that, Yaron Minsky and Stephen Weeks from Jane Street Capital talks about their experiences with functional programming on Wall Street. Wadler quotes from the article:
When we first tried switching over from VB to C#, one of the most disturbing features of the language for the partners who read the code was inheritance. They found it difficult to figure out which implementation of a given method was being invoked from a given call point, and therefore, difficult to reason about the code. It is worth mentioning that OCaml actually does support inheritance as part of its object system. That said, objects are an obscure part of the language, and inheritance even more so. At Jane Street, we almost never use objects and never use inheritance. We use standard functional programming techniques and code reviewers find that style more comprehensible. In particular, they can reason by following static properties of the code (module boundaries and functor applications) rather than dynamic properties (what class an object is).

This made me think of F#, which is inspired by OCaml. Will users of F# tend to not use any OO, just as in Jane Street Capital? Or, put in another way, will F# users tend to only be consumers of OO code (i.e., the .NET framework) and provide a "nice" OO-style API for client code, but "underneath the surface" focus entirerly on the functional part of F#?

Media: Wadler does a funny thing, in the very last minute of his talk (Faith, Evolution, and Programming Languages).

Attending events

Tomorrow I will attend SweNug Gbg for the first time. Exciting! I had a real good time at the open space (in Gothenburg) one month ago and I'm hoping that tomorrow will be fun as well. But it's not without sacrifices: I'll have to catch the earliest train to Ystad (@ 05.40) to attend a driving lesson on Thursday.

On 3 October, I will attend Microsofts half-day on data access, in Malmö, where Erik Meijer and Jimmy Nilsson will talk. Erik Meijer is one of the (many) reasons that I chose to focus on .NET rather than Java. After you read this post, go and read all his papers! :)

A funny quote from the event page:
[...] in the first half of the last century, mathematicians invented monads, which have subsequently migrated to the computer science mainstream via functional programming (mainly Haskell) and have recently shown up as LINQ in C# 3.0 and Visual Basic.
Jimmy Nilsson is the author of Applying Domain-Driven Design and Patterns, which I read this summer, great book! And, by the way, Jimmy is the second best developer in Sweden (rated by ComputerSweden).

Finally, a note-to-self: try to write shorter posts and more often.

Saturday, September 6, 2008

ClickOnce deployment or not?

Some weeks ago, I developed a small program in C# called P4 Explorer. To distribute it, i used a technique called ClickOnce deployment, which is a part of Visual Studio C# Express 2008. This blog post will be about what ClickOnce deployments are, how they can be used, and why you in the end shouldn't use them...

ClickOnce deployments will simplify your deployment a lot. To deploy your application, all you need to do is:
  1. specify the location to publish the application (i.e. a network drive, web site or ftp),
  2. specify from what location the users will install it from (propably the same as 1), and
  3. decide whether the application should be installed at the start menu, or always must be started from the install path (2).
Furhermore you can specify if the application automatically should check for updates, which is really great if you plan to update your application frequently. You then specify how often the it should check for updates, and when an update is found, the user will be notified and can download the latest version. All by only selecting "The application should check for updates". Very nice!

Now, for you to deploy a new version, all you do is click "Publish". When the user then starts the program, the update will be found and installed (if permitted by the user). Very easy!

Application Path
ClickOnce deployment doesn't come for free though. First of, the application won't be installed under "C:\Program Files\MyCompany\MySoftware" as you might expect, but at some secret place (hidden from the user and developer). If you decide to let the installer add a shortcut to your start menu, there is no way to find out where this shortcut points, as it's not a normal shortcut. Right clicking on it and selecting properties will not give you the information you expect, i.e. the path to the executable.
Now, there is a simple way of finding out the path of the executable. When starting the installed application, the property Application.ExecutablePath will be correctly set and you can thus be used to, for example, add to the PATH environment variable:
void UpgradePathVariable()
string l_ApplicationFolder = Path.GetDirectoryName(Application.ExecutablePath);
string l_PathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
if (!l_PathVariable.Contains(l_ApplicationFolder))
l_PathVariable = l_OldPathVariable + ";" + l_ApplicationFolder;
Environment.SetEnvironmentVariable("PATH", l_PathVariable, EnvironmentVariableTarget.Machine);

Also, because the program doesn't have a fixed installation path, there is no support for sending parameters to the program. I.e. args in static void Main(string[] args) will always be empty. The documentation at MSDN states that the only way to send parameters to a click once application is to deploy it at a web page, and let the user send html-parameters to it, i.e.:
  1. this requires your application to be deployed using a web page, and
  2. you must always download the installer every time you need to sent parameters to the program.
Say for example you want to let the user start the program by right clicking on a file in explorer and selecting "Open in my program". You would need to add a line in your registry pointing to the executable file:

pathtoyourexe "%1"

This would be both slow and hacky if using the recommended http-style mentioned above. Instead, by using the Application.ExecutablePath property, you can actually access the physical path to the installed executable, and thus add this path to the registry. With this setup correctly, right clicking on a file and selecting your program to open it with, will open the program and send the parameter correctly to it!

But, even though everything might seem to work out fine, you will soon notice that the Settings object defined in your application will be different if starting the program using the shortcut from your start menu, or right clicking on a file. They are not sharing the same application settings. And if you upgrade the program, all settings in your "right clicked version" will be gone, because the new version will be installed in a new folder.

In the end
Even though click once applications are really easy to deploy, and give you a lot for free, the limitations just makes them really hard to work with. Making simple applications might work, but as soon as you want the user to interact with it through the explorer shell, you are better off making your own installer (or using a free one such as NSIS). So in the end I decided to deploy my program manually using a source control, which made all my problems go away. Sending parameters worked, settings worked, and the application had a fixed folder!

The only thing I was really missing from ClickOnce was the ability for the program to automatically check for updates, which was something I really needed to make sure everyone using my application had the latest version (hopefully having less bugs in it). But it turned out this wasn't so hard to make on my own! The pseudo code for it, printed here, is divided in two programs - your main application, yourapp.exe, and the upgrade application, upgrade.exe.

  1. Is there a new version available (i.e. check using source control)
  2. Copy upgrade.exe (and dependencies) to a new folder "temp"
  3. Start new process temp\upgrade.exe
  4. Close program
  1. Make sure all instances of yourapp.exe are closed
  2. Download the latest version (i.e. using source control)
  3. Start new process ..\yourapp.exe
  4. Close program
You can always make it faster by running the check for new version in it's own thread, and only checking every x hour, but the main thing is that I get the same features as if running with ClickOnce, but don't need to limit my application as much as you do with ClickOnce applications!

So, ClickOnce, good for small application, not good for more advanced applications.