3

using let inline and member constraints I'll be able to make duck typing for known members but what if I would like to define a generic function like so:

let duckwrapper<'a> duck = ...

with the signature 'b -> 'a and where the returned value would be an object that implemented 'a (which would be an interface) and forwarded the calls to duck.

I've done this in C# using Reflection.Emit but I'm wondering if F# reflection, quotations or other constructs would make it easier.

Any suggestions on how to accomplish this?

EDIT after reading Tims answer I thought I'd give a bit more details

What I was thinking of when I wrote about using quotations to help was something like:

{new IInterface with member x.SayHello() = !!<@ %expr @>}

!! being an operator translating the quotation to a function and %expr being the unit of work for the method. I'd be able to translate the expression to a function (I guess) but wouldn't know how to

of course this wouldn't do the trick completely either since IInterface would be 'a which is where I hope F# reflection might have some handy functions so that I could construct a type based on a type object and some function values

EDIT As an update to Tomas Petricek answer I'll give some code to explain my needs

type SourceRole =
   abstract transfer : decimal -> context

and context(sourceAccount:account, destinationAccount) =
   let source = sourceAccount
   let destination = destinationAccount

   member self.transfer amount = 
     let sourcePlayer = 
       {new SourceRole with
          member this.transfer amount =
              use scope =  new TransactionScope()
              let source = source.decreaseBalance amount
              let destination = destination.increaseBalance amount
              scope.Complete()
              context(source,destination)
              }
     sourcePlayer.transfer(amount)

which is a try at porting "the" textbook example of DCI in F#. The source and destination are DCI roles. It's the idea that any data object that adhere's to a specific contract can play those. In this case the contract is simple. source needs a memberfunction called decreaseBalance and destination needs a member function called increaseBalance. I can accomplish that for this specific case with let inline and member constraints. But I'd like to write a set of functions that given an interface and an object. In this case it could be source (as the object) and

type sourceContract = 
   abstract decreaseBalance : decimal -> sourceContract

as the type. The result would be an object of type sourceContract that would pipe method calls to a method with the same name on the source object.

Rune FS
  • 21,497
  • 7
  • 62
  • 96
  • See my edit in response to your edit. F# reflection can't generate code. F# quotations aren't powerful enough for what you want. Reflection.Emit is the right thing to use here. – Tim Robinson Dec 14 '10 at 15:12
  • F# uses structural typing, not duck typing. They are very similar in that they both use type inference, but structural typing is static while duck typing is dynamic (there are other differences as well). It sounds like what you want to do would be accomplished with a functor in OCaml, but I'm not sure what the F# equivalent would be. – Niki Yoshiuchi Dec 14 '10 at 16:46
  • You can maybe also use .NET Remoting for this. – Brian Dec 14 '10 at 16:49
  • @Brian Remoting proxies are another way to implement duck typing. However this approach is much slower than generating a wrapper class in memory. – Tim Robinson Dec 14 '10 at 18:28
  • @Niki my task (and hence the question) relates to making duck typing possible. Structural typing requires the structure of two types to be identical duck typing requires the part used at run time to be identical. I'm only concerned about the part used at runtime aka duck typing – Rune FS Dec 15 '10 at 13:12

2 Answers2

4

F# reflection (Microsoft.FSharp.Reflection) is an F#-friendly wrapper around the plain System.Reflection APIs, so I don't think it would add anything here.

Quotations can't define new types: (you'd need to define a new type to do your interface-based duck typing)

> <@ { new IInterface with member x.SayHello = "hello" } @>;;

  <@ { new IInterface with member x.SayHello = "hello" } @>;;
  ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(7,4): error FS0449: Quotations cannot contain object expressions
> <@ type Test() = class end @>;;

  <@ type Test() = class end @>;;
  ---^^^^

stdin(8,4): error FS0010: Unexpected keyword 'type' in quotation literal

Reflection.Emit is still the way to go with this.

Edit:

I hope F# reflection might have some handy functions so that I could construct a type based on a type object and some function values

I'm afraid it doesn't. Here's the documentation on F# reflection: http://msdn.microsoft.com/en-gb/library/ee353491.aspx

Tim Robinson
  • 53,480
  • 10
  • 121
  • 138
2

You can compile F# quotations using components from F# PowerPack. So I think you could use quotations to generate and execute code at runtime. If you write a quotation representing a function & compile it you'll get a function value that you could use to implement an interface. Here is a trivial example:

#r "FSharp.PowerPack.Linq.dll"
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

// Create a part using "Expr." calls explicitly
let expr = Expr.Value(13)
// Create a part using quotation syntax 
let expr2 = <@ (fun x -> x * %%expr) @>

// Compile & Run
let f = expr2.Compile()()
f 10

You can mix quotation syntax and calls to Expr, which makes it easier to compose code from basic blocks. The compilation is a bit stupid (currently) so the generated code won't be as efficient as usual F# code (but you'll need to measure it in your case).

I'm not quite sure I understand what exactly are you trying to do, so if you can provide more details, I can give more specific answer.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • That's very much a long the lines of what I was thinking. I've updated my question with some sample code – Rune FS Dec 15 '10 at 09:59