Posts Tagged ‘language design’

Extension methods are so cool

Wednesday, March 25th, 2009

Enums in the C-family of languages have always been a little…anemic. Much better than a handful of ints, but anemic. If you want any actual behavior out of them, you either end up with a bag of functions stashed somewhere “convenient”, or rolling your own enum-like behavior in a full-on class.

C# 3.0′s extension methods bring first-class citizenship to enums, albeit in a way that reminds me more of Haskell’s modules than of C# classes. Now we can have member functions for enum values!

(Hey Microsoft, any hope for an EnumOutOfRangeException when someone tries to cast an unsuitable int? Please?)

F# is disappointing

Sunday, March 22nd, 2009

I’ve been gradually coming to the conclusion that I’d rather use LINQ than F#, both because it’s more pleasant and because it better fits what I want from a functional language.

There are all sorts of factors that contribute to this, large and small. Some examples:

  • F#’s laziness is difficult to use, and must be explicitly declared
  • I end up wrestling with F# over types, even in situations where Haskell, my gold standard for a fiercely-typed language, can cope. For instance, one cannot add an integer to a BigInt, or compare them for size.
  • “;;”. At the coders’ social, I had this discussion with the two friends I’d recruited to work with me:
    • me: “Interpreter lines end with semicolon-semicolon”
    • them: “What are they using semicolon for?”
    • me: “List separation”
    • them: “Then what are they using comma for?”
    • me: “Tuple separation”
    • them: “But… semicolon semicolon? Why?”
    • me: *hopeless shrug*
  • Recursive functions must be recursively declared, making them the
    marked state.
  • The built-in List library doesn’t contain half the functions I look
    for, like take, drop, and their higher-order cousins: takeWhile and
    dropWhile.
  • Casually printing temporary results is annoying, requiring both
    “printfn” (“print” doesn’t appear to be taken) and strict typecasting.
  • List.zip requires lists of the same length. (This and non-laziness being the default mean that my most common zip-using scenarios don’t work in F#.)

And, of course, the lovely example I just spent five minutes on:
List.zip [1, 2, 3] [3, 4, 5];;
val it : ((int * int * int) * (int * int * int)) list
= [((1, 2, 3), (3, 4, 5))]
I’d expected a list of pairs.

The problem turned out to be, ironically, too much implicit behavior: [1, 2, 3] is interpreted as [(1, 2, 3)]. I’d much rather have the implicit behavior that lets me compute 12345678I > 0.