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.)
// 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 =
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.