Search code examples
f#type-providers

F# - Can I reference "this" or "self" in a type provider?


I'm trying to create a type provider that inherits from this type:

type BaseType() =
    member val Member : string = "" with get, set

But I don't know how to reference Member using "this" or "base", say, in the constructor. Here's an example of what I'm trying to do:

[<TypeProvider>]
type BasicProvider (config : TypeProviderConfig) as this =
    inherit TypeProviderForNamespaces ()

    let asm, ns = Assembly.GetExecutingAssembly(), "Namespace"

    let createTypes () = 
        let myType = ProvidedTypeDefinition (asm, ns, "ProvidedType", Some typeof<BaseType>)
        let ctor =
            ProvidedConstructor [
                ProvidedParameter("inputString", typeof<string>) ]
        do ctor.InvokeCode <-
            fun parameters ->
                // base.Member doesn't actually work - how can one do this?
                <@@ do (base: BaseType).Member <- (%%parameters.[0]: string) @@>
        do myType.AddMembers [ctor]
        [myType]
    do this.AddNamespace(ns, createTypes())

Is there any way to do what I'm trying to do when I say "base.Member" there?

If not, is there a different recommended way to store internal state in a provided type?


Solution

  • I have not tested this, but I think something like the following should do the trick:

    ctor.InvokeCode <- fun parameters ->
      <@@ let res = BaseType()
          res.Member <- (%%parameters.[0]: string) 
          res @@>
    

    The expression passed to InvokeCode of a constructor does not mean the body of a constructor of a new type (if you are creating erasing type provider) - it just needs to be any expression that returns a value of the type that you are erasing to. This means that you can put more complex initialization code in the expression.

    I personally prefer keeping the inline quotations simpler, so I'd have a library function:

    let createBaseType (input:string) = 
      BaseType(Member = input)
    

    And call the helper from a quotation:

    ctor.InvokeCode <- fun parameters ->  
      <@@ createBaseType (%%parameters.[0]) @@>
    

    However, this is just a matter of style - both options should work.