I just read the information on this page, and while a new ? operator is mentioned, it's quite unclear to me what would its usage be.
Could anyone please provide a quick explanation, post a code snipped of how would this operator be used and possibly mention a use case?
Edit: this is really awkward, I've noticed that the ? operator is no longer mentioned in Don's release notes. Any idea of why is that?

- 6,088
- 6
- 48
- 80
3 Answers
There are two new "special" operators in this F# release, (?) and (?<-). They are not defined, but they are available for overloading, so you can define them yourself. The special bit is how they treat their 2nd operand: they require it to be a valid F# identifier, but pass it to function implementing the operator as a string. In other words:
a?b
is desugared to:
(?) a "b"
and:
a?b <- c
is desugared to:
(?<-) a "b" c
A very simple definition of those operators could be:
let inline (?) (obj: 'a) (propName: string) : 'b =
let propInfo = typeof<'a>.GetProperty(propName)
propInfo.GetValue(obj, null) :?> 'b
let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
let propInfo = typeof<'a>.GetProperty(propName)
propInfo.SetValue(obj, value, null)
Note that since the return type for the gettor is generic, you'll have to specify it at use site in most cases, i.e.:
let name = foo?Name : string
though you can still chain-call (?) (since first argument of (?) is also generic):
let len = foo?Name?Length : int
Another, more interesting, implementation is to re-use CallByName method provided by VB:
open Microsoft.VisualBasic
let inline (?) (obj: 'a) (propName: string) : 'b =
Interaction.CallByName(obj, propName, CallType.Get, null) :?> 'b //'
let inline (?<-) (obj: 'a) (propName: string) (value: 'b) =
Interaction.CallByName(obj, propName, CallType.Set, [| (value :> obj) |])
|> ignore
The advantage of that is that it will handle both properties and fields correctly, work with IDispatch COM objects, etc.

- 117,631
- 17
- 236
- 300

- 99,783
- 25
- 219
- 289
-
1As a side note, apparently, F# PowerPack includes a reasonable default implementation. – Pavel Minaev Nov 26 '09 at 00:57
It sounds like the "?" operator relates to the Dynamic Language Runtime (DLR). That is, you use it when you want to bind to an object member (method, property) at runtime, rather than at compile time.
It's funny because I was hoping that this would be how dynamic member invocation would work in C# also. Alas, C# exposes this functionality via a "pseudo" type ("dynamic" IIRC). In my opinion, this makes the code somewhat less clear (because you have to track down the variable declaration to know if the call is early-bound or late-bound).
I don't know the exact syntax, but if I had to guess, it either replaces or augments the "." (dot) operator. As in:
let x = foo?Bar()
or maybe:
let x = foo.?Bar()

- 12,007
- 2
- 44
- 61
-
1"because you have to track down the variable declaration to know if the call is early-bound or late-bound"... You don't have to track very far. dynamic must be a local variable and cannot be a type member; if you have to scroll very far to find out whether or not a variable is dynamic, chances are you need to refactor. Plus the IDE will gladly tell you the type if you hover over the name of a variable... – Randolpho May 21 '09 at 00:19
-
2Good points. For what it's worth, there is another reason I'd prefer a "late-bound call" operator over the "dynamic" type implementation: Given that it is possible to hook into the DLR by implementing an interface, I can imagine a scenario where you would like to do early-bound calls and late-bound calls on the same reference. – Daniel Pratt May 21 '09 at 00:44
-
Out of curiosity what should be the type of foo and why would I want to do that instead of foo.Bar()? Besides, can't I already achieve the same result via reflection? – em70 May 21 '09 at 10:16
-
@emaster70 I doubt the type of the reference matters. And yes, in most cases you could accomplish the same thing with reflection, however such code is hard to write and even harder to read. Also, I think the DLR will support scenarios that reflection does not. For example, I seem to recall a DLR demo of C# interacting with an object defined in JavaScript. – Daniel Pratt May 21 '09 at 13:04
There is a module FSharp.Interop.Dynamic, on nuget that implements the dynamic operator using the dlr.
let ex1 = ExpandoObject() in
ex1?Test<-"Hi";
ex1?Test |> should equal "Hi";
It's open source, Apache license, you can look at the implementation and it includes unit test example cases.

- 31,383
- 12
- 95
- 128