anchor.diff:  type SampleVariants =
       | None = 0x0
       | Bias = 0x1
  -    
  -
  -let memberFunctionAttributesDefaultArgs (comment : string) (attributes : Option<string>) (variants : SampleVariants) (name : string)
  -                                        (args : list<string * string * Option<string>>) (ret : string) =
  -    let args =
  -        args |> List.map (fun (n,t,o) ->
  -            match o with
  -            | Some def -> sprintf "[<Optional; DefaultParameterValue(%s)>] %s : %s" def n t
  -            | _ -> sprintf "%s : %s" n t
  -        ) |> String.concat ", "
  -
  -
  -    line "/// %s" comment
  -
  -    match attributes with
  -    | Some attr -> line "%s" attr
  -    | _ -> ()
  -
  -    line "member x.%s(%s) : %s = onlyInShaderCode \"%s\"" name args ret name
  -    line ""
  -
  -    if (variants &&& SampleVariants.Bias) <> SampleVariants.None then
  -        line "/// %s with lod-bias" comment
  -        line "member x.%s(%s, lodBias : float) : %s = onlyInShaderCode \"%s\"" name args ret name
  +
  +type Argument =
  +    { Name : string
  +      Type : string
  +      DefaultValue : Option<string> }
  +
  +    override x.ToString() =
  +        match x.DefaultValue with
  +        | Some def -> sprintf "[<Optional; DefaultParameterValue(%s)>] %s : %s" def x.Name x.Type
  +        | _ -> sprintf "%s : %s" x.Name x.Type
  +
  +
  +module Argument =
  +    let create (name : string) (typ : string) (defaultValue : Option<String>) =
  +        { Name = name; Type = typ; DefaultValue = defaultValue }
  +
  +    let simple (name : string) (typ : string) =
  +        { Name = name; Type = typ; DefaultValue = None }
  +
  +
  +[<Sealed; AbstractClass>]
  +type Write private() =
  +
  +    static member MemberFunction(name : string, arguments : list<Argument>, returnType : string,
  +                                 [<Optional; DefaultParameterValue(null : string)>] comment : string,
  +                                 [<Optional; DefaultParameterValue(null : string)>] attributes : string,
  +                                 [<Optional; DefaultParameterValue(SampleVariants.None)>] variants : SampleVariants) =
  +        let args =
  +            arguments |> List.map string |> String.concat ", "
  +
  +        if not <| comment.IsNullOrEmpty() then
  +            line "/// %s" comment
  +
  +        if not <| attributes.IsNullOrEmpty() then
  +            line "%s" attributes
  +
  +        line "member x.%s(%s) : %s = onlyInShaderCode \"%s\"" name args returnType name
           line ""
   
  -let memberFunctionDefaultArgs (comment : string) (variants : SampleVariants) (name : string)
  -                              (args : list<string * string * Option<string>>) (ret : string) =
  -    memberFunctionAttributesDefaultArgs comment None variants name args ret
  -
  -let memberFunctionAttributes (comment : string) (attributes : Option<string>) (variants : SampleVariants)
  -                             (name : string) (args : list<string * string>) (ret : string) =
  -    let args = args |> List.map (fun (n, t) -> n, t, None)
  -    memberFunctionAttributesDefaultArgs comment attributes variants name args ret
  -
  -let memberFunction (comment : string) (variants : SampleVariants)
  -                   (name : string) (args : list<string * string>) (ret : string) =
  -    memberFunctionAttributes comment None variants name args ret
  -
  -let propertyDefaultArgs (comment : string) (name : string) (setter : Option<String>) (args : list<string * string * Option<string>>) (ret : string) =
  -    let args =
  -        args |> List.map (fun (n,t,o) ->
  -            match o with
  -            | Some def -> sprintf "[<Optional; DefaultParameterValue(%s)>] %s : %s" def n t
  -            | _ -> sprintf "%s : %s" n t
  -        ) |> String.concat ", "
  -
  -    line "/// %s" comment
  -    line "member x.Item"
  -    line "    with get (%s) : %s = onlyInShaderCode \"%s\"" args ret name
  -
  -    match setter with
  -    | Some name ->
  -        line "    and set (%s) (data : %s) : unit = onlyInShaderCode \"%s\"" args ret name
  -    | _ ->
  -        ()
  -
  -    line ""
  -
  -let property (comment : string) (name : string) (setter : Option<String>) (args : list<string * string>) (ret : string) =
  -    let args = args |> List.map (fun (n, t) -> n, t, None)
  -    propertyDefaultArgs comment name setter args ret
  +        if (variants &&& SampleVariants.Bias) <> SampleVariants.None then
  +            line "/// %s with lod-bias" comment
  +            line "member x.%s(%s, lodBias : float) : %s = onlyInShaderCode \"%s\"" name args returnType name
  +            line ""
  +
  +    static member MemberFunction(name : string, arguments : list<string * string>, returnType : string,
  +                                [<Optional; DefaultParameterValue(null : string)>] comment : string,
  +                                [<Optional; DefaultParameterValue(null : string)>] attributes : string,
  +                                [<Optional; DefaultParameterValue(SampleVariants.None)>] variants : SampleVariants) =
  +        let arguments = arguments |> List.map (fun (n, t) -> Argument.simple n t)
  +        Write.MemberFunction(name, arguments, returnType, comment, attributes, variants)
  +
  +    static member MemberFunction(name : string, arguments : list<string * string * Option<string>>, returnType : string,
  +                                [<Optional; DefaultParameterValue(null : string)>] comment : string,
  +                                [<Optional; DefaultParameterValue(null : string)>] attributes : string,
  +                                [<Optional; DefaultParameterValue(SampleVariants.None)>] variants : SampleVariants) =
  +        let arguments = arguments |> List.map (fun (n, t, d) -> Argument.create n t d)
  +        Write.MemberFunction(name, arguments, returnType, comment, attributes, variants)
  +
  +
  +    static member Property(name : string, arguments : list<Argument>, returnType : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] setter : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] comment : string) =
  +        let args =
  +            arguments |> List.map string |> String.concat ", "
  +
  +        if not <| comment.IsNullOrEmpty() then
  +            line "/// %s" comment
  +
  +        line "member x.Item"
  +        line "    with get (%s) : %s = onlyInShaderCode \"%s\"" args returnType name
  +
  +        if not <| setter.IsNullOrEmpty() then
  +            line "    and set (%s) (data : %s) : unit = onlyInShaderCode \"%s\"" args returnType setter
  +
  +        line ""
  +
  +    static member Property(name : string, arguments : list<string * string>, returnType : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] setter : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] comment : string) =
  +        let arguments = arguments |> List.map (fun (n, t) -> Argument.simple n t)
  +        Write.Property(name, arguments, returnType, setter, comment)
  +
  +    static member Property(name : string, arguments : list<string * string * Option<string>>, returnType : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] setter : string,
  +                           [<Optional; DefaultParameterValue(null : string)>] comment : string) =
  +        let arguments = arguments |> List.map (fun (n, t, d) -> Argument.create n t d)
  +        Write.Property(name, arguments, returnType, setter, comment)
  +
   
   let floatVec (c : int) =
       match c with
  
positive.code: open System.IO
  open FShade
  open Aardvark.Base
  open System.Runtime.CompilerServices
  
  
  let namespaceName = "FShade"
  
  let types = [ SamplerType.Float; SamplerType.Int ]
  let dims = [ SamplerDimension.Sampler1d; SamplerDimension.Sampler2d; SamplerDimension.Sampler3d; SamplerDimension.SamplerCube]
  
negative.code: 
          let itemArgs = args |> List.map (fun (n,t) -> sprintf "%s : %s" n t) |> String.concat ", "
  
          Write.MemberFunction(
              "Load",
              args,
              returnType,
              comment = "load single texel from image"
          )
  
          Write.MemberFunction(
              "Store",
              (args @ ["data", returnType]),
              "unit",
              comment = "write single texel into image",
              attributes = "[<FShade.Imperative.KeepCall>]"
          )
  
          Write.Property(
              "Load",
              args,
              returnType,
              setter = "Store",
              comment = "access single texel of image"
          )
  
          if t = SamplerType.Int then
              line "member x.AtomicAdd(%s, data : int) : int = onlyInShaderCode \"AtomicAdd\"" itemArgs
  