Tuesday, July 20, 2010

F#'s Little-Known (?) and (?<-) Operators

(Note: After posting this, I found a blog entry where Matthew Podwysocki uses a similar Dictionary<> example. I commend you to his more complete discussion of the dynamic operators at Using and Abusing the F# Dynamic Lookup Operator; it's well worth looking at. Vladimir Matveev has also just posted an article on dynamic lookup operators; I highly recommend it as well: Tricky late binding operators. And, since it never rains unless it pours, there is also a recent article by Tomas Petricek at hubFS which uses dymanic operators to great advantage in a real-world problem: Dynamic in F#: Reading data from SQL database. Dynamic is certainly a dynamic topic right now!)

This post is about a pair of F# operators that – unless you interface with dynamic programming languages or use reflection a lot – you’ve probably never encountered. These are the dynamic reflection operators, (?) and (?<-). Their main function is to clean up the syntax of dynamic language interfaces and domain-specific languages.

These two operators work similar to the C/C++ “stringizing” pre-processor operator. That is, they convert non-string code (limited to simple identifiers in the case of F#) into strings according to the following translation patterns:

e0?str =translates to=> e0 “str” and
e0?str<-e1 =translates to=> e0 “str” e1

In typical use, (?) is used create “get” operation, and (?<-) is used to create a “set” operation. Normally, this is done to provide a convenient interface to dynamic code.* In the canonical examples, this method is used to invoke a member by name on an instance loaded or created by reflection. But to simplify things a bit, the example below shows their use on a Dictionary<>. (As always, all the code here is presented "as-is" and without warranty or implied fitness of any kind; use at your own risk.)

open System.Collections.Generic
// Please note that this is a contrived example
// for illustration only!  There are better
// ways to accomplish what I'm doing here,
// and more appropriate uses of (?) and (?<-).
// Define (?) and (?<-) for 
// Dictionary<> access:
/// Lookup an item and return it,
/// or throw KeyNotFoundException.
let (?) (d:Dictionary<string,'T>) k =
/// Set or reset an item.
let (?<-) (d:Dictionary<string,'T>) k v =
// Test.
let num = new Dictionary<string,int>()
// For example, func?plus21 <- (+) 21
// translates to: (?<-) func "plus21" ((+) 21) 
num?one <- 1
num?two <- 2
num?twenty <- 20
let fortyTwo = (num?one+num?twenty)*num?two
//let iWillFail = func?four 
printfn "Your breakpoint here."

In Expert F# 2.0, Don Syme (et al) caution against injudicious use of this pair of operators. In particular, there are concerns of type safety and performance in dynamic programming. You lose good stuff like some type checking, autocomplete, etc. Dynamic programming syntax helpers can result in code that looks as fast as compiled code yet masks underlying runtime expense. Also, many users will rarely encounter the (?) and (?<-) operators may be confused on encountering them in code.

On the flip side, these operators can make ugly code a lot more readable. So, if you need to interface with dynamic code, or clean up some aspects of a domain-specific language, there they are.


*The generated names of these operators are op_Dynamic and op_DynamicAssignment.


Vladimir Matveev said...

Some less known facts about these operators:Tricky late binding operators. Maybe you will find it useful.

TechNeilogy said...

Thank you! I have added a paragraph to the beginning of the post which points readers to your blog about this, as well as a couple of others. I recommend all readers here check out Vladimir's excellent post and blog.