Search code examples
f#type-providers

Can you run code before creating a type provider? (F#)


Say:

let x = // some operation
type t = SomeTypeProvider<x>

Is this valid?


Solution

  • No.

    Since the types must be generated at compile-time, the parameter to the type provider needs to be a constant.

    In other words, the code you marked // some operation can evaluate to a literal, but cannot be a value returned by a runnable function:

    let arg = "foo"
    type t = SomeTypeProvider<arg> // okay
    
    let [<Literal>] arg = """{"name":"foo","value":42}"""
    type t = SomeTypeProvider<arg> // okay
    
    let arg = x.ToString()
    type t = SomeTypeProvider<arg> // Boom! arg is not a Literal
    

    It depends on your application, but one of the most common cases is the following:

    You have a database-related Type Provider, and the connection string needs to be retrieved in runtime, from some sort of config file or something. So a developer mistakenly thinks they need a runnable code to retrieve the connection string first and then pass it to the Type Provider.

    The correct approach is the following:

    Keep two databases: one locally stored in a constant location (just for schema), and another one for the runtime purposes.
    Pass the first one (a constant!) to your Type Provider. Don't worry about the hardcoded paths; it is only used for schema retrieval.

    // Use a fixed sample file for schema generation only
    type MyCSVData = CsvProvider<"dummy.csv">
    
    // Load the actual data at runtime
    let data = MyCSVData.Load(RetrieveFileNameFromConfig())