Skip to content

Instantly share code, notes, and snippets.

@baronfel
Last active May 18, 2020 18:56
Show Gist options
  • Save baronfel/58d9699351fc97e2a908a99de60085cf to your computer and use it in GitHub Desktop.
Save baronfel/58d9699351fc97e2a908a99de60085cf to your computer and use it in GitHub Desktop.
deconstruct tinkering
type Wrapper() =
let mutable _one = 0
let mutable _two = 0
member _.one
with get () = _one
and set (newValue: int) =
_one <- newValue
member _.two
with get () = _two
and set (newValue: int) =
_two <- newValue
/// C#-style deconstructor
member this.Deconstruct(one: _ outref, two: _ outref) =
one <- this.one
two <- this.two
// /// this basically does what the F# compiler does for outref 't parameters anyway when you call them:
// /// initialize a cell for the value, and pass the address in to the called member
// member inline this.Deconstruct() =
// let mutable one = Unchecked.defaultof<_>
// let mutable two = Unchecked.defaultof<_>
// this.Deconstruct(&one, &two)
// struct(one, two)
let inline de< ^ty, ^inputs, ^outputs when ^ty: (member Deconstruct: ^inputs -> ^outputs) > (w: ^ty) =
( ^ty: (member Deconstruct: ^inputs -> ^outputs) (w, Unchecked.defaultof< ^inputs >))
let inline deUnit< ^ty, ^outputs when ^ty: (member Deconstruct: unit -> ^outputs) > (w: ^ty) =
( ^ty: (member Deconstruct: unit -> ^outputs) (w))
let w = Wrapper()
match w.Deconstruct() with
| (one, two) -> printfn "%d %d" one two
// match deUnit w with
// | (one, two) -> printfn "%d %d" one two
// error on the `de` invocation here is:
// The member or object constructor 'Deconstruct' takes 2 argument(s) but is here given 1.
// The required signature is 'member Wrapper.Deconstruct : one:outref<int> * two:outref<int> -> unit'
match de w with
| (one, two) -> printfn "%d %d" one two
/// idea of what to do to enable F#+-style inline usage for arbitrary deconstruct overloads
type Deconstruct =
static member inline Invoke f =
let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member Deconstruct: _*_ -> _) b, a)
call_2 (Unchecked.defaultof<Deconstruct>, Unchecked.defaultof<'t>) f
static member Deconstruct (deconstructorFn: 'a outref -> unit, _: Deconstruct) =
let mutable a = Unchecked.defaultof<'a>
deconstructorFn &a
a
static member Deconstruct (deconstructorFn: 'a outref * 'b outref -> unit, _: Deconstruct) =
let mutable a = Unchecked.defaultof<'a>
let mutable b = Unchecked.defaultof<'b>
deconstructorFn (&a, &b)
/// this works at the call-site, but then the deconstructorFn parameters error with:
/// The parameter 'deconstructorFn' has an invalid type '(outref<'a> -> unit)'. This is not permitted by the rules of Common IL.F# Compiler(3300)
let inline decon (item: 't) = Deconstruct.Invoke item
a, b
@abelbraaksma
Copy link

printfn "%d"

I assume you meant printfn "%d" d, right? (sorry, no answers yet on your slack q.)

@baronfel
Copy link
Author

yeah :) I've updated the gist with that fix + some further tinkering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment