Friday, June 19, 2009

Generating strong repeatable GUIDs

In recent weeks I've had the problem of wanting to generate GUIDs that are distinct, but are repeatable -- in particular for things like COM class UIDs, and for installer component IDs, for a project using a lot of generated code.

So this is what I did in part of my build scripts (note, this is not totally RFC 4122 compliant, but it suffices in practice)

The input is the individual name of the thing I'm generating, concatenated with a constant GUID string used as a salt. The ToUpperInvariant is there to permit WiX to be run in pedantic mode.

Yes, it's exactly as vulnerable to hash collisions as MD5 -- but then my input is not maliciously aiming at such.

Later:-- or you could just use

but that makes the RFC 4122 guid-for-salt explicit for you.

Links for 19-Jun

The event-based asynchronous pattern -- introduction and implementation.

Interleaving work to keep threads responsive.

PowerBoots 0.2 -- WPF in PowerShell (v1 as well as v2).

Mixing languages -- the right tool for the right job.

Is this assembly built as debug?

The elusive tail opcode in F# -- a cautionary tale about debug builds.

Sunday, June 07, 2009

Scala on .net — not ready for serious use... least with Scala 2.7.3, and what it gets for sbaz scala-msil in any case.

Having written (well, ported) a moderate amount of Scala code over the last few weeks, towards an experiment in cross-VM code (using my tidied up version of the C# port of the to-Erlang jinterface library as the template), I thought it was time to start with the serious porting experiment.

Have you ever read the Arabian Nights (like the full thing e.g. the Penguin Classics version)?

The format goes roughly

def Quest(p : Problem) : Resolution = {
  val helper = Helper.WiseMan(p)
  helper.Ask(p) match {
     case p2 : Some[Problem] => helper.Resolve (
               Quest(p2.get()) // almost always this branch
     case None => helper.Resolve()

and so it feels with this task.

The obvious way to model the threading and mailbox code in the library is to use the scala.actors library. But that's not in predef.dll -- the source is part Java, part Scala. Noting that Scala 2.7.5 has some fixes for actors, I start with that code base.

Step 1 -- use the Java conversion assistant, build as C#, fixing up all the missing bits, then try to build the Scala code against it. It reports an abject failure to find the generated equivalent of Runnable.

Step 2 -- move the classes in SupportClass.cs into the scala.actors namespace, and rebuild. The shows up all the Java classes used in the Scala code, but also yields up the assertion that the FJTask class is broken:

4@(06 1f 09 02)
error: error while loading FJTask, type 'scala.actors.FJTask' is broken
(1f@2 in (06 1f 09 02))

-- I've not looked to what the IL means in this context. This happened even when compiling the C# with the .net 1.0 compiler.

Step 3 -- bite the bullet and port the Java code to Scala as a standalone project, with .net system calls. Fairly simple to do. Get all the syntactical errors out and the compilation throws an exception trying to do something with Object.wait()

Cannot find method class Object::wait
scope = {
  def this(): System.Object;
  protected def finalize(): Unit;
  def hashCode(): Int;
  def toString(): System.String;
  protected def MemberwiseClone(): System.Object;
  def GetType(): System.Type;
  def equals(System.Object): Boolean;
  final def ==(System.Object): Boolean;
  final def !=(System.Object): Boolean;
  final def eq(System.Object): Boolean;
  final def ne(System.Object): Boolean;
  final def synchronized(System.Object): System.Object;
  final def $isInstanceOf[T0 >: ? <: ?](): Boolean;
  final def $asInstanceOf[T0 >: ? <: ?](): T0;
  def clone(): System.Object;
  def wait(): Unit;
  def wait(Long): Unit;
  def wait(Long,Int): Unit;
  def notify(): Unit;
  def notifyAll(): Unit
Exception in thread "main" java.lang.Error: System.Object.wait

-- and that's after I've replaced all the instances of such a call with Monitor.Wait(), and the same for Object.notify() going to Monitor.Pulse(). But in order to get this far, I had to remove every instance of private[package-name]; and while the @volatile attribute seemed to be accepted as syntax, the emitted MSIL did not honour this decoration.

Pretty much at a dead end here.

Out of curiosity, I tried building the Erlang-bridge library I was originally intending to build for both platforms. After a little bit of tidying away calls to (java.lang.)String.format(), the compilation throws again, this time complaining about trait Projection in the context of the DigitsArray helper class (which HAS A rather than IS A Array[Int]) for immutable BigIntegers (intended to substitute for the lack of same on .net, at least this side of .net4). And this with code that passes unit tests with 90%+ coverage on the JVM.

class DigitsArray
  symbol = final class DigitsArray
  owner  = final <module> <package> <java> package platform
with methods = List(com.ravnaandtines.platform.DigitsArray.<init>, com.ravnaandt
ines.platform.DigitsArray.ShiftLeft, com.ravnaandtines.platform.DigitsArray.Shif
tRight, com.ravnaandtines.platform.DigitsArray.FreeBits, com.ravnaandtines.platf
orm.DigitsArray.getSlack, com.ravnaandtines.platform.DigitsArray.tailCountNegati
ve, com.ravnaandtines.platform.DigitsArray.GetDataUsed, com.ravnaandtines.platfo
rm.DigitsArray.ResetDataUsed, com.ravnaandtines.platform.DigitsArray.length, com
.ravnaandtines.platform.DigitsArray.update, com.ravnaandtines.platform.DigitsArr
ay.apply, com.ravnaandtines.platform.DigitsArray.DataUsed, com.ravnaandtines.pla
tform.DigitsArray.IsZero, com.ravnaandtines.platform.DigitsArray.IsNegative, com
.ravnaandtines.platform.DigitsArray.toString, com.ravnaandtines.platform.DigitsA
rray.hashCode, com.ravnaandtines.platform.DigitsArray.equals, com.ravnaandtines.
platform.DigitsArray.AsIterator, com.ravnaandtines.platform.DigitsArray.AsSeq, c
om.ravnaandtines.platform.DigitsArray.lead, com.ravnaandtines.platform.DigitsArr
ay.consistent, com.ravnaandtines.platform.DigitsArray.<init>, com.ravnaandtines.
platform.DigitsArray.<init>, com.ravnaandtines.platform.DigitsArray.<init>, com.
ravnaandtines.platform.DigitsArray.<init>, com.ravnaandtines.platform.DigitsArra$ravnaandtines$platform$DigitsArray$$data, com.ravnaandtines.platform.Digit
sArray.dataUsed_$eq, com.ravnaandtines.platform.DigitsArray.dataUsed, com.ravnaa
Exception in thread "main" java.lang.Error: trait Projection
  symbol = abstract <interface> <trait> trait Projection
  owner  = final <module> object Array with name scala.Array.Projection

Reality check -- redo last year's cross-platform experiments ("hello world", and a Python/Scala stack). They still work just fine.

If the compiler worked, then it would be quite simple to port the Actors library. There would need to be some alternate code for the Debug.scala and FJTaskScheduler2.scala calls to java.lang.System; and applying some consistency to whether java.lang is explicitly or implicitly imported (simplest if always implicit, for the awkwardly inconsistent use of imports for Runnable and InterruptedException. Working around the fact that System.Threading.Thread is sealed is fairly easy.

I tried this, and the exception I get, with just stubs for the Java classes is

object Eval$2
  symbol = final case <module> object Eval$2
  owner  = final <module> object Futures
with methods = List(scala.actors.Futures.Eval$2.<init>, scala.actors.Futures.Eva
l$2.readResolve, scala.actors.Futures.Eval$2.productElement, scala.actors.Future
s.Eval$2.productArity, scala.actors.Futures.Eval$2.productPrefix, scala.actors.F
utures.Eval$2.toString, scala.actors.Futures.Eval$2.$tag)
Exception in thread "main" java.lang.RuntimeException
        at ch.epfl.lamp.compiler.msil.emit.ILGenerator.emit(ILGenerator.scala:48

which refers to unmodifed code from the Scala actors library!

As it is, after the first easy side-quest to get the Actors library, the next side-quest would be the serious work of extending the compiler-to-MSIL. Alas, compilers are one of those bits of the field that I've never dabbled in before. So that'd be the next level of side-quest...

Other people ("Hi, Ivan!") seem to have gotten as far as the "Hello world!" stage too, but I've not seen any other reports of anything serious being attempted.

Which is a pity, since I quite like the language -- it's not as spiky as Erlang or as gnomic as F#, while allowing you functional style goodness, even if it is not fully a functional language in the truest sense (everything is an object, even functions).

Later -- test cases uploaded to my Mediafire WorksInProgress folder; the various build.bat files in provoke different crashes.