Tuesday, August 01, 2006

.Net: it is you and your abilities the Emperor wants

I haven't mentioned my ongoing .Net indoctrination in a while. I decided to exercise my sub-Padawan F# muscles by reimplementing one of our simplest but still useful portlets. The actual code wasn't anything special: get data, format and show data. The harder part was working out how to write in F# such that the portal would recognize it like a portlet written in the recommended C#. At first, I couldn't get it to work no matter how I futzed with the class declarations, until I realized that by default I was compiling to generic-friendly 2.0, and not the portal's supported 1.1 - d'oh!

An interesting case study of F# vs. C# was my use of Printf.sprintf to substitute parameters into my SQL statement (no, the parameters did not come in from the user, I have heard of SQL injection attacks). The compiler kept complaining every time I tried to separately store the pre-interpolated SQL as a string. It kept telling me, through the handy "mouse over a variable for a type tooltip" F# VS feature, that the first parameter to Printf.sprintf was of type 'a Printf.string_format, or something like that. Eventually the message got through my thick noggin: at compile time Printf.sprintf somehow transforms its first string argument into a function that takes a series of specifically-typed parameters! I had two ways of doing the interpolation: use Printf.sprintf by storing the SQL as a static method that just returns the SQL with a type annotation of 'a Printf.string_format, or use the .Net String.Format method by storing the SQL as an immutable plain string member variable, initialized in the constructor. Either way, I'm storing the SQL as an immutable at the class level.

Some other little tidbits from the experience:
  • The general form of the code was "class member function equals pattern match on argument evaluates to let-binding of intermediate step in let-binding of intermediate step in expression to save to a Page mutable property". In other words, for a class method, perform a data transformation through repeated function application and then use an expression with a side-effect to save the transformation result.
  • Normally a single F# source file becomes a module, but if you want to go C#-style and use the file to declare a namespace with internal class definitions, just put a 'namespace' line at the top and only declare types (such as classes) at the file's top level.
  • Watch out for nulls creeping into your code through variables from non-F# .Net APIs! The very handy ?? binary operator appears to return its left argument if it is not null and the right argument if it is. null can also be used in pattern matches.
  • F# does not appear to support the usual class access modifiers as other .Net languages. Well, it supports only one, I guess: public. F# (and OCaml, I believe) use a different way to hide implementation: signature files, which seem a bit like a C++ header file containing prototypes.
I think it's clear that for frameworks as heavily object-centric as ASP.Net, F# implementations may not be as compelling, since it isn't a context in which F#'s strengths can be best leveraged. To be fair, I'm still a novice at using F#'s object system, so it could also be that I didn't know what I was doing. I could see F# being an excellent language for a library that could be called from ASP.Net, however. F# is not a mere OO language in the crowd for .Net. Presumably the people at Microsoft wanted F# for its unique identity and abilities.

No comments:

Post a Comment