Idiomatic constructors in F#

f#, inline

Solution

You're right -- if you want to define optional parameters for a method, you need to define the arguments in tupled form. One way you could approach this would be to move the implementation of your `Create` method into a private method (and rename it, e.g., to `CreateImpl`), then re-define `Create` as an overloaded method which will simply dispatch to the implementation. For example:

type VAO =
    { Handle : int }

    static member private CreateImpl (vboList, ibo : _ option) =
        failwith "Not implemented."

    static member Create vboList =
        VAO.CreateImpl (vboList, None)

    static member Create (vboList, ibo) =
        VAO.CreateImpl (vboList, Some ibo)

Another approach, is to define a module (it needs to be placed below the definition of your `VAO` type) which defines curried functions which "wrap" the static `VBO.Create(...)` method. This'll work however you decide to declare the arguments for `Create` (i.e., using a single method with tuple-style argument declaration and optional parameters, or using the overloading approach described above). For example, if you don't use my overloading method, and decide to just define `Create` as `static member Create (vboList, ?ibo)`:

// The [<CompilationRepresentation>] attribute is necessary here, because it allows us to
// define a module which has the same name as our type without upsetting the compiler.
// It does this by suffixing "Module" to the type name when the assembly is compiled.
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix>]
module VAO =
    let create (vboList : _ list) =
        VAO.Create vboList

    let createWithIndex vboList ibo =
        VAO.Create (vboList, ibo)

Those module functions are very simple, so it's very likely they'll be inlined automatically by the F# compiler and you won't pay any run-time costs for them. If you compile in `Release` mode, inspect the assembly's IL and find that's not the case, then you can add the `inline` keyword to the function definitions to force them to be inlined. (Best not to do force inlining unless you benchmark and are certain it offers a real performance gain.)

One tip, unrelated to your question about the optional arguments -- consider re-defining at least some of your types as structs rather than F# records. Record types are compiled into classes (i.e., reference types) so you pay the additional indirection cost for no reason; defining them as structs will eliminate this indirection and give your application better performance. Better yet, if you're able to, re-use one of the existing OpenGL wrapper libraries like OpenTK or OpenGL4Net.

Problem

I started with a small OpenGL wrapper and I run into a small problem. I usally create my data with records like this ``` type Shader = { Handle : int } static member Create filepath stype = let h = loadshader filepath stype { Handle = h } type VertexShader = { shader : Shader } static member Create path = { shader = Shader.Create path ShaderType.VertexShader } type FragmentShader = { shader : Shader } static member Create path = { shader = Shader.Create path ShaderType.FragmentShader } ``` I am always using a static constructor with a non tupled function. But now I want another type where I would like to have optional parameters. like ``` type VAO = { Handle : int } static member Create vboList ?ibo = ........ ``` The problem is that this doesn't seem to be possible with non-tupled functions and I don't want to mix my Create methods with tupled and non-tupled functions. I wonder if I even wrote idiomatic F# code in the first place. How would you approach this "problem"?

Original source