Admiral Genesis
Admiral Genesis

Reputation: 33

how is discriminated unions (pure) implemented in f#

I wonder if they are simply using a number to represent each cases, or they will be compiled to control flows (if statements) that helps decide the matter

pure means the cases aren't of any data types

I tried looking for answers on stack overflow but I didn't find any

Upvotes: 0

Views: 176

Answers (1)

Maku
Maku

Reputation: 1558

In general yes, each case is a number (called Tag in the implementation). It's easy to figure out how some things are realized in F# by decompiling F# assembly to C#.

E.g.

Union type defined like this:

type UnionType = This | That of int

Decompiles to C# like this (I cut out interface implementations at the bottom as it is pretty lengthy, you can easily repeat this process yourself):

[Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[DebuggerDisplay("{__DebugDisplay(),nq}")]
[CompilationMapping(SourceConstructFlags.SumType)]
public abstract class UnionType : IEquatable<UnionType>, IStructuralEquatable, IComparable<UnionType>, IComparable, IStructuralComparable
{
    public static class Tags
    {
        public const int This = 0;

        public const int That = 1;
    }

    [Serializable]
    [SpecialName]
    [DebuggerTypeProxy(typeof(_This@DebugTypeProxy))]
    [DebuggerDisplay("{__DebugDisplay(),nq}")]
    internal class _This : UnionType
    {
        [CompilerGenerated]
        [DebuggerNonUserCode]
        internal _This()
        {
        }
    }

    [Serializable]
    [SpecialName]
    [DebuggerTypeProxy(typeof(That@DebugTypeProxy))]
    [DebuggerDisplay("{__DebugDisplay(),nq}")]
    public class That : UnionType
    {
        [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
        [CompilerGenerated]
        [DebuggerNonUserCode]
        internal readonly int item;

        [CompilationMapping(SourceConstructFlags.Field, 1, 0)]
        [CompilerGenerated]
        [DebuggerNonUserCode]
        public int Item
        {
            [CompilerGenerated]
            [DebuggerNonUserCode]
            get
            {
                return item;
            }
        }

        [CompilerGenerated]
        [DebuggerNonUserCode]
        internal That(int item)
        {
            this.item = item;
        }
    }

    [SpecialName]
    internal class _This@DebugTypeProxy
    {
        [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
        [CompilerGenerated]
        [DebuggerNonUserCode]
        internal _This _obj;

        [CompilerGenerated]
        [DebuggerNonUserCode]
        public _This@DebugTypeProxy(_This obj)
        {
            _obj = obj;
        }
    }

    [SpecialName]
    internal class That@DebugTypeProxy
    {
        [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
        [CompilerGenerated]
        [DebuggerNonUserCode]
        internal That _obj;

        [CompilationMapping(SourceConstructFlags.Field, 1, 0)]
        [CompilerGenerated]
        [DebuggerNonUserCode]
        public int Item
        {
            [CompilerGenerated]
            [DebuggerNonUserCode]
            get
            {
                return _obj.item;
            }
        }

        [CompilerGenerated]
        [DebuggerNonUserCode]
        public That@DebugTypeProxy(That obj)
        {
            _obj = obj;
        }
    }

    [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
    [CompilerGenerated]
    [DebuggerNonUserCode]
    internal static readonly UnionType _unique_This = new _This();

    [CompilerGenerated]
    [DebuggerNonUserCode]
    [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
    public int Tag
    {
        [CompilerGenerated]
        [DebuggerNonUserCode]
        get
        {
            return (this is That) ? 1 : 0;
        }
    }

    [CompilerGenerated]
    [DebuggerNonUserCode]
    [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
    public static UnionType This
    {
        [CompilationMapping(SourceConstructFlags.UnionCase, 0)]
        get
        {
            return _unique_This;
        }
    }

    [CompilerGenerated]
    [DebuggerNonUserCode]
    [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
    public bool IsThis
    {
        [CompilerGenerated]
        [DebuggerNonUserCode]
        get
        {
            return this is _This;
        }
    }

    [CompilerGenerated]
    [DebuggerNonUserCode]
    [DebuggerBrowsable(/*Could not decode attribute arguments.*/)]
    public bool IsThat
    {
        [CompilerGenerated]
        [DebuggerNonUserCode]
        get
        {
            return this is That;
        }
    }

    [CompilerGenerated]
    [DebuggerNonUserCode]
    internal UnionType()
    {
    }

    [CompilationMapping(SourceConstructFlags.UnionCase, 1)]
    public static UnionType NewThat(int item)
    {
        return new That(item);
    }

    /* cut out members including interface implementations */

}

Upvotes: 1

Related Questions