Skip to content

Instantly share code, notes, and snippets.

@Happypig375
Last active April 29, 2022 09:12
Show Gist options
  • Save Happypig375/db80980bbfa5715ebf7ebcb41e472643 to your computer and use it in GitHub Desktop.
Save Happypig375/db80980bbfa5715ebf7ebcb41e472643 to your computer and use it in GitHub Desktop.
Type switching in F#
[SharpLab.Runtime.JitGeneric(typeof(int))]
[SharpLab.Runtime.JitGeneric(typeof(long))]
[SharpLab.Runtime.JitGeneric(typeof(byte))]
void f<T>(T x) {
if (typeof(T) == typeof(bool)) System.Console.WriteLine((bool)(object)x);
else if (typeof(T) == typeof(int)) System.Console.WriteLine((int)(object)x);
else if (typeof(T) == typeof(long)) System.Console.WriteLine((long)(object)x);
}
[SharpLab.Runtime.JitGeneric(typeof(int))]
[SharpLab.Runtime.JitGeneric(typeof(long))]
[SharpLab.Runtime.JitGeneric(typeof(byte))]
T g<T>(T x) {
if (typeof(T) == typeof(int)) return (T)(object)((int)(object)x + 1);
else if (typeof(T) == typeof(long)) return (T)(object)((long)(object)x + 1L);
else throw null;
}
/*
; Core CLR 6.0.322.12309 on x86
<Program>$.<Main>$(System.String[])
L0000: ret
<Program>$.<<Main>$>g__f|0_0[[System.Int32, System.Private.CoreLib]](Int32)
L0000: push ebp
L0001: mov ebp, esp
L0003: call System.Console.WriteLine(Int32)
L0008: pop ebp
L0009: ret
<Program>$.<<Main>$>g__f|0_0[[System.Int64, System.Private.CoreLib]](Int64)
L0000: push ebp
L0001: mov ebp, esp
L0003: push dword ptr [ebp+0xc]
L0006: push dword ptr [ebp+8]
L0009: call System.Console.WriteLine(Int64)
L000e: pop ebp
L000f: ret 8
<Program>$.<<Main>$>g__f|0_0[[System.Byte, System.Private.CoreLib]](Byte)
L0000: push ebp
L0001: mov ebp, esp
L0003: pop ebp
L0004: ret
<Program>$.<<Main>$>g__g|0_1[[System.Int32, System.Private.CoreLib]](Int32)
L0000: push ebp
L0001: mov ebp, esp
L0003: lea eax, [ecx+1]
L0006: pop ebp
L0007: ret
<Program>$.<<Main>$>g__g|0_1[[System.Int64, System.Private.CoreLib]](Int64)
L0000: push ebp
L0001: mov ebp, esp
L0003: mov eax, [ebp+8]
L0006: mov edx, [ebp+0xc]
L0009: add eax, 1
L000c: adc edx, 0
L000f: pop ebp
L0010: ret 8
<Program>$.<<Main>$>g__g|0_1[[System.Byte, System.Private.CoreLib]](Byte)
L0000: push ebp
L0001: mov ebp, esp
L0003: xor ecx, ecx
L0005: call 0x727a19f0
L000a: int3
*/
let inline typeBranch (x: 'T) ([<InlineIfLambda>] thenBranch : 'U -> 'V) ([<InlineIfLambda>] elseBranch : unit -> 'W) =
if System.Type.(=)(typeof<'T>, typeof<'U>) then
x |> box |> LanguagePrimitives.IntrinsicFunctions.UnboxFast<'U>
|> thenBranch |> box |> LanguagePrimitives.IntrinsicFunctions.UnboxFast<'W>
else elseBranch()
[<SharpLab.Runtime.JitGeneric(typeof<int>)>]
[<SharpLab.Runtime.JitGeneric(typeof<int64>)>]
[<SharpLab.Runtime.JitGeneric(typeof<byte>)>]
let f (x: 'T): unit =
typeBranch x (System.Console.WriteLine : bool -> unit) <| fun () ->
typeBranch x (System.Console.WriteLine : int -> unit) <| fun () ->
typeBranch x (System.Console.WriteLine : int64 -> unit) <| fun () ->
()
[<SharpLab.Runtime.JitGeneric(typeof<int>)>]
[<SharpLab.Runtime.JitGeneric(typeof<int64>)>]
[<SharpLab.Runtime.JitGeneric(typeof<byte>)>]
let g (x: 'T): 'T =
typeBranch x ((+) 1) <| fun () ->
typeBranch x ((+) 1L) <| fun () ->
raise null
(*
; Core CLR 6.0.322.12309 on x86
_.typeBranch(!!0, Microsoft.FSharp.Core.FSharpFunc`2<!!1,!!2>, Microsoft.FSharp.Core.FSharpFunc`2<Microsoft.FSharp.Core.Unit,!!3>)
; Open generics cannot be JIT-compiled.
; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types.
; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M<T>() { ... }.
_.f[[System.Int32, System.Private.CoreLib]](Int32)
L0000: push ebp
L0001: mov ebp, esp
L0003: call System.Console.WriteLine(Int32)
L0008: pop ebp
L0009: ret
_.f[[System.Int64, System.Private.CoreLib]](Int64)
L0000: push ebp
L0001: mov ebp, esp
L0003: push dword ptr [ebp+0xc]
L0006: push dword ptr [ebp+8]
L0009: call System.Console.WriteLine(Int64)
L000e: pop ebp
L000f: ret 8
_.f[[System.Byte, System.Private.CoreLib]](Byte)
L0000: push ebp
L0001: mov ebp, esp
L0003: pop ebp
L0004: ret
_.g[[System.Int32, System.Private.CoreLib]](Int32)
L0000: push ebp
L0001: mov ebp, esp
L0003: lea eax, [ecx+1]
L0006: pop ebp
L0007: ret
_.g[[System.Int64, System.Private.CoreLib]](Int64)
L0000: push ebp
L0001: mov ebp, esp
L0003: mov eax, [ebp+8]
L0006: mov edx, [ebp+0xc]
L0009: add eax, 1
L000c: adc edx, 0
L000f: pop ebp
L0010: ret 8
_.g[[System.Byte, System.Private.CoreLib]](Byte)
L0000: push ebp
L0001: mov ebp, esp
L0003: xor ecx, ecx
L0005: call 0x727a19f0
L000a: int3
*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment