Saturday, October 2, 2010

Notes from getting Scala running on .NET

I just spend an evening getting Scala to run on .NET 4.0. Here my notes:

Scala 2.8.0

I started downloading Scala 2.8.0-final as a zip file (), and unpacking it to my scala playground directory. That gave me:
PS C:\Scala-playground\scala-2.8.0.final> tree
Folder PATH listing for volume OSDisk
Volume serial number is 00690066 6A5B:A532
C:.
+---bin
+---doc
¦   +---sbaz
¦   +---sbaz-setup
+---lib
+---meta
¦   +---cache
+---misc
¦   +---sbaz
¦   ¦   +---config
¦   ¦   +---descriptors
¦   +---sbaz-testall
¦   ¦   +---tests
¦   +---scala-devel
¦   ¦   +---plugins
¦   +---scala-tool-support
¦       +---a2ps
¦       +---bash-completion
¦       +---bluefish
¦       +---context
¦       ¦   +---Highlighters
¦       ¦   +---Template
¦       +---emacs
¦       ¦   +---contrib
¦       +---enscript
¦       +---geshi
¦       +---intellij
¦       +---jedit
¦       ¦   +---console
¦       ¦   ¦   +---commando
¦       ¦   +---modes
¦       +---latex
¦       +---notepad-plus
¦       +---scite
¦       +---subethaedit
¦       ¦   +---artwork
¦       ¦   +---Scala.mode
¦       ¦       +---Contents
¦       ¦           +---Resources
¦       ¦               +---English.lproj
¦       ¦               +---Scripts
¦       +---textmate
¦       ¦   +---Bundles
¦       +---textpad
¦       +---textwrangler
¦       +---ultraedit
¦       +---vim
¦           +---ftdetect
¦           +---indent
¦           +---plugin
¦           +---syntax
+---src

I then went on to install the Scala msil extension (i.e. the scala .NET compiler and runtime) as follows:
PS C:\Scala-playground\scala-2.8.0.final> bin/sbaz.bat install scala-msil

Then, following the "official" instructions on running scala on .NET (http://www.scala-lang.org/node/168), I copied mscorlib.dll to the scala lib folder:
PS C:\Scala-playground\scala-2.8.0.final> copy C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll .\lib

I was now ready to try to compile something. E.g. this very simple hello world program using a little bit of .NET, namely Console.WriteLine:

import System.Console object test extends Application {   Console.WriteLine("Hello world!") }

I tried to compile it like this:
PS C:\Scala-playground\hello.net> ..\scala-2.8.0.final\bin\scalac.bat -target:msil .\test.scala

but got this error:
scala.tools.nsc.MissingRequirementError: class scala.runtime.VolatileBooleanRef not found.
        at scala.tools.nsc.symtab.Definitions$definitions$.getModuleOrClass(Definitions.scala:513)
        at scala.tools.nsc.symtab.Definitions$definitions$.getClass(Definitions.scala:471)
        at scala.tools.nsc.symtab.Definitions$definitions$.newValueClass(Definitions.scala:620)
        at scala.tools.nsc.symtab.Definitions$definitions$.BooleanClass(Definitions.scala:92)
        at scala.tools.nsc.symtab.Definitions$definitions$.initValueClasses(Definitions.scala:643)
        at scala.tools.nsc.symtab.Definitions$definitions$.init(Definitions.scala:787)
        at scala.tools.nsc.Global$Run.(Global.scala:597)
        at scala.tools.nsc.Main$.process(Main.scala:107)
        at scala.tools.nsc.Main$.main(Main.scala:122)
        at scala.tools.nsc.Main.main(Main.scala)
error: fatal error: class scala.runtime.VolatileBooleanRef not found.

I tried like this to point out where mscorlib and the scala runtime dlls are:
PS C:\Scala-playground\hello.net> ..\scala-2.8.0.final\bin\scalac.bat -target:msil -Xassem-extdirs ..\scala-2.8.0.final\lib .\test.scala
scala.tools.nsc.MissingRequirementError: class scala.runtime.VolatileBooleanRef not found.
        at scala.tools.nsc.symtab.Definitions$definitions$.getModuleOrClass(Definitions.scala:513)
        at scala.tools.nsc.symtab.Definitions$definitions$.getClass(Definitions.scala:471)
        at scala.tools.nsc.symtab.Definitions$definitions$.newValueClass(Definitions.scala:620)
        at scala.tools.nsc.symtab.Definitions$definitions$.BooleanClass(Definitions.scala:92)
        at scala.tools.nsc.symtab.Definitions$definitions$.initValueClasses(Definitions.scala:643)
        at scala.tools.nsc.symtab.Definitions$definitions$.init(Definitions.scala:787)
        at scala.tools.nsc.Global$Run.(Global.scala:597)
        at scala.tools.nsc.Main$.process(Main.scala:107)
        at scala.tools.nsc.Main$.main(Main.scala:122)
        at scala.tools.nsc.Main.main(Main.scala)
error: fatal error: class scala.runtime.VolatileBooleanRef not found.
..same error.

Then I resorted to frantic googling, but ended up deciding to downgrade the mscorlib.dll to 2.0, and to 1.1. But in both cases I got same depressing result.
Finally I decided to downgrade to scala 2.7.7.

Scala 2.7.7

I downloaded scala 2.7.7 unzipped it and got:
PS C:\Scala-playground\scala-2.7.7.final> tree
Folder PATH listing for volume OSDisk
Volume serial number is 00690066 6A5B:A532
C:.
+---bin
+---doc
¦   +---sbaz
¦   +---sbaz-setup
+---lib
+---meta
¦   +---cache
+---misc
¦   +---sbaz
¦   ¦   +---descriptors
¦   +---sbaz-testall
¦   ¦   +---tests
¦   +---scala-tool-support
¦       +---a2ps
¦       +---bluefish
¦       +---context
¦       ¦   +---Highlighters
¦       ¦   +---Template
¦       +---emacs
¦       ¦   +---contrib
¦       +---enscript
¦       +---geshi
¦       +---intellij
¦       +---jedit
¦       ¦   +---console
¦       ¦   ¦   +---commando
¦       ¦   +---modes
¦       +---latex
¦       +---notepad-plus
¦       +---scite
¦       +---subethaedit
¦       ¦   +---artwork
¦       ¦   +---Scala.mode
¦       ¦       +---Contents
¦       ¦           +---Resources
¦       ¦               +---English.lproj
¦       ¦               +---Scripts
¦       +---textmate
¦       ¦   +---Bundles
¦       +---textpad
¦       +---textwrangler
¦       +---ultraedit
¦       +---vim
¦           +---ftdetect
¦           +---indent
¦           +---plugin
¦           +---syntax
+---src
The I went through copying mscorlib and installing scala-msil again:
PS C:\Scala-playground\scala-2.7.7.final> copy C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll .\lib
PS C:\Scala-playground\scala-2.7.7.final> .\bin\sbaz.bat install scala-msil
planning to install: scala-msil/2.7.7.final
Installing...

Then I tried compilling again:
PS C:\Scala-playground\hello.net> ..\scala-2.7.7.final\bin\scalac-net.bat .\test.scala
PS C:\Scala-playground\hello.net> ls


    Directory: C:\Scala-playground\hello.net


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        30-09-2010     21:59            target
-a---        30-09-2010     22:33       3863 test.msil
-a---        30-09-2010     21:52        100 test.scala

which went well. The scala compiler made a .msil file. Yeah.

Next step was turning that .msil into an .exe:
PS C:\Scala-playground\hello.net> C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe .\test.msil

Microsoft (R) .NET Framework IL Assembler.  Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling '.\test.msil'  to EXE --> '.\test.exe'
Source file is ANSI

Assembled method test::$tag
Assembled method test::main
Assembled method test$::.ctor
Assembled method test$::.cctor
Assembled method test$::$tag
Assembled method test$::main
Assembled global method Main
Creating PE file

Emitting classes:
Class 1:        test
Class 2:        test$

Emitting fields and methods:
Global  Methods: 1;
Class 1 Methods: 2;
Class 2 Fields: 1;      Methods: 4;
Resolving local member refs: 8 -> 8 defs, 0 refs, 0 unresolved

Emitting events and properties:
Global
Class 1
Class 2
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

Which gave:
PS C:\Scala-playground\hello.net> ls


    Directory: C:\Scala-playground\hello.net


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        30-09-2010     21:59            target
-a---        30-09-2010     22:35       2560 test.exe
-a---        30-09-2010     22:33       3863 test.msil
-a---        30-09-2010     21:52        100 test.scala

So I tried running the program:
PS C:\Scala-playground\hello.net> .\test.exe

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'predef, Version=0.0.0.0, Culture=
neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at Main(String[] args)

but missed the predef assembly which is part of the scala-msil extension. To get passed that I simply copied all dlls from the Scala lib folder and ran again:
PS C:\Scala-playground\hello.net> mv .\test.exe .\target
PS C:\Scala-playground\hello.net> cp ..\scala-2.7.7.final\lib/*.dll .\target
PS C:\Scala-playground\hello.net> cd .\target
PS C:\Scala-playground\hello.net\target> ls

    Directory: C:\Scala-playground\hello.net\target


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        30-09-2010     22:30    2070528 mscorlib.dll
-a---        30-09-2010     22:30    1180160 predef.dll
-a---        30-09-2010     22:30       5632 scalaruntime.dll
-a---        30-09-2010     22:35       2560 test.exe
PS C:\Scala-playground\hello.net\target> .\test.exe
Hello world!

Success! but only on the next to newest Scala version. Either way I had fun :-)

Saturday, September 25, 2010

Spec Style Unit Tests in C#

Spec style unit tests are unit tests that focus on making the specs clear, and then relating some test code to each part of the spec. The Specs Scala unit test framework is really good at that (e.g. check this earlier post), but I want to be able to do the same in C#.


Lets look at an example: A method for deciding whether a given year is a leap year. The rules for leap years are:


A leap year should
    be any year divisible by 400
    but not other years divisible by 100
    and all other years divisible by 4


In other words the above are the specs for the method. So I would like that to be clear from the unit test. I would also like the unit test to make it clear what test code corresponds to what part of the spec. Therefore I would like the spec to be part of the test, and the test code to be mixed right into that spec text. Something like:


"A leap year" should
{
  "be any year divisible by 400" asIn
{
// test code here
}
  "but not other years divisible by 100" asIn
{
// test code here
}
  "and all other years divisible by 4" asIn
{
// test code here
}
}


such that the spec is clearly visible as the strings, and such that the 'asIn' indicates that the code in the following scope tests the part of the spec right before the 'asIn'. To achieve something close to this I've made three simple extension methods on string: 'should', 'asIn' and 'andIn'. Each one of these extension methods take a delegate as an argument. That makes it possible to write this code:

   16             "A leap year".should(() =>
   17             {
   18                 "be any year divisible by 400".asIn(() =>
   19                 {
   20                     // Test code here
   21 
   22                 })
   23                 .andIn(() =>
   24                 {
   25                     // More test code
   26                 });
   27 
   28                 "but not other years divisible by 100".asIn(() =>
   29                 {
   30                     // Test code here
   31                 });
   32 
   33                 "and all other years divisible by 4".asIn(() =>
   34                 {
   35                     // Test code here
   36                 })
   37 

Because this is C# there I need to the dots and the arrows ( ()=> ) in there, but I still think the spec is pretty clearly visible. The extension methods themselves are very simple: They basically just execute the delegate passed to them, which means that all the test code snippets in the above will be executed. The complete code for the extension methods is:




    1 using System;
    2 
    3 namespace Specs
    4 {
    5     public static class SpecExtensions
    6     {
    7         public static void should(this string unitUnderTest,
    8                                   Action executableSpecification)
    9         {
   10             Console.WriteLine(unitUnderTest + " should");
   11             executableSpecification();
   12         }
   13 
   14         public static string asIn(this string readableSpecification,
   15                                   Action executableSpecification)
   16         {
   17             Console.WriteLine(@"    " + readableSpecification);
   18             return RunExecutableSpecification(
   19                     readableSpecification, executableSpecification);
   20         }
   21 
   22         public static string andIn(
   23             this string readableSpecification,
   24             Action executableSpecification)
   25         {
   26             return RunExecutableSpecification(
   27                     readableSpecification, executableSpecification);
   28         }
   29 
   30         private static string RunExecutableSpecification(
   31             string readableSpecification,
   32             Action executableSpecification)
   33         {
   34             executableSpecification();
   35             return readableSpecification;
   36         }
   37     }
   38 }


Combining that with NUnit, the test for my leap year checker becomes:




    1 using NUnit.Framework;
    2 
    3 namespace Specs.Test
    4 {
    5     [TestFixture]
    6     public class LeapYearTest
    7     {
    8         [Test]
    9         public void LeapYearSpec()
   10         {
   11             "A leap year".should(() =>
   12             {
   13                 "be any year divisible by 400".asIn(() =>
   14                 {
   15                     Assert.That(LeapYearChecker.IsLeapYear(0),
   16                                 Is.True);
   17                     Assert.That(LeapYearChecker.IsLeapYear(400),
   18                                 Is.True);
   19                     Assert.That(LeapYearChecker.IsLeapYear(800),
   20                                 Is.True);
   21                 })
   22                 .andIn(() =>
   23                 {
   24                     Assert.That(LeapYearChecker.IsLeapYear(-400),
   25                                 Is.False);
   26                 });
   27 
   28                 "but not other years divisible by 100".asIn(() =>
   29                 {
   30                     Assert.That(LeapYearChecker.IsLeapYear(100),
   31                                 Is.False);
   32                     Assert.That(LeapYearChecker.IsLeapYear(100),
   33                                 Is.False);
   34                     Assert.That(LeapYearChecker.IsLeapYear(200),
   35                                 Is.False);
   36                     Assert.That(LeapYearChecker.IsLeapYear(1000),
   37                                 Is.False);
   38                 });
   39 
   40                 "and all other years divisible by 4".asIn(() =>
   41                 {
   42                     for (int i = 0; i < 100; i += 4)
   43                     {
   44                         Assert.That(LeapYearChecker.IsLeapYear(i),
   45                                     Is.True);
   46                     }
   47                 })
   48                 .andIn(() =>
   49                 {
   50                     for (int i = 1600; i < 1700; i += 4)
   51                     {
   52                         Assert.That(LeapYearChecker.IsLeapYear(i),
   53                                     Is.True);
   54                     }
   55                 })
   56                 .andIn(() =>
   57                 {
   58                     for (int i = 1601; i < 1700; i += 4)
   59                     {
   60                         Assert.That(LeapYearChecker.IsLeapYear(i),
   61                                     Is.False);
   62                     }
   63                 });
   64             });
   65         }
   66     }
   67 

The specs are not as easily visible once all the code is there, but I still think its easy to find the specs. What do you think? Is there too much clutter of dots and arrows and stuff? Is the calling back and forth between the test and extension methods too strange? I'm on the fence. One part me really, really likes this. One part of me really, really doesn't.
Oh, and for completeness the code under test is:




    1    public static class LeapYearChecker
    2     {
    3         public static bool IsLeapYear(int year)
    4         {
    5             return year >= 0 &&
    6                 (year % 400 == 0 ||
    7                 (year % 4 == 0 && year % 100 != 0));
    8         }
    9     }

Thursday, September 9, 2010

Don't Stay Stuck

If you write code professionally, you will have days where you find yourself utterly stuck on a problem. In fact, some days coding feels like trying to wade through quicksand: The harder you struggle to get out the more stuck you find yourself. Getting into one of those situations where you are stuck and can't find a way out is perfectly normal. And it is perfectly acceptable for a professional programmer as well. Every programmer finds themselves in those situations from time to time. Getting stuck is a natural part of creative work like programming, and as such we must simply accept that we get utterly stuck now and then. The important part is what you do about it. As with quicksand the trick is to relax a bit, sit back, and realize that you need to seek help. Not all programmers realize this, but the best ones do.
When faced with an insurmountable problem some programmers just press on and try to work through it. That usually means they start thrashing; they run around in circles without getting anywhere. While this might keep them warm, and even make them seem really busy and hard working it doesn't help the project. Some programmers sort of lose interest and start surfing the web or drinking inordinate amounts of coffee. That doesn't help the project either. To get out the situation you're stuck in, you probably need help - I know, I always do. So seek help.
Seeking help can mean a number of things depending on the problem you're facing. If the problem is on the code level try asking a teammate to come and pair with you - or if you're already pairing, ask to switch pairing partner - that extra set of eyes usually helps. If the problem is a design issue, again ask a teammate to help you out, but get up from the keyboard and go to the white board. Again the extra set of eyes - or even just the process of explaining the problem - usually helps. If the problem isn't technical but has to do with say access to the right tools, the right level of support from third parties, or unrealistic deadlines, ask your project manager for help. And if he or she is not able or willing to help, don't be afraid to escalate the problem to his or her boss - it's the professional thing to do. As I said: Seeking help can mean a number of different things.
But whatever you do, don't just stay stuck. Do something about it.