Skip to content

union (a sum type)

SyntaxDescription
abstract record Shape; record Circle(float R) : Shape;Declaration and value generation
s switch { Circle c => ..., _ => ... }Branching by type
s switch { Circle c => ..., Rect r => ... }Branching without a default case
A a => ..., B b => ..., C c => ...Branching over 3 or more types
s is CircleTesting for a specific type
void Use(Shape s)Receiving as a parameter
Shape Make()Returning as a return value
Shape[] all = new Shape[2];Array element
SyntaxDescriptionErrorReasonInstead
private Shape held;Holding as a fieldTUKI0001not yetPass it via a local variable, argument, or array
record Pair(Node L, Node R) : Node;A definition that includes itself (recursion)TUKI0001runtimeRepresent a tree with an array and indices
Debug.Log(s)Passing a union value out as isTUKI0001runtimeBranch by type first, then pass the extracted value
A union value can’t be held in a field. To keep it as state, put the enum value that represents the kind and each type’s contents in separate fields.

An interface attached to a value type (struct / record) is converted to this same form. Both become a single number that represents which type is currently held, plus storage for each type, laid out in sequence. Only the way it’s written differs; the underlying mechanism is the same. Only an interface attached to a Behaviour uses a different mechanism — it points to the Behaviour itself.

Each type’s storage is separate; they don’t overlap. The number of slots a union uses is the sum of every type’s contents, plus one for the number that represents the kind. It isn’t sized to match the largest type. Adding one more type increases the count by that type’s contents (for the slot limit, see Udon’s execution model).

Declare the base with abstract record, and declare each type with a record that inherits from that base.

using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnDeclare : TsukimiBehaviour
{
void Start()
{
Shape s = new Circle(1f);
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
_ => 0f,
};
Debug.Log(a); // => 1
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnSwitchWithDefault : TsukimiBehaviour
{
void Start()
{
Shape s = new Rect(2f, 3f);
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
_ => 0f,
};
Debug.Log(a); // => 6
}
}

If the cases are exhaustive, you don’t need a default case.

using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnSwitchExhaustive : TsukimiBehaviour
{
void Start()
{
Shape s = new Circle(1f);
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
};
Debug.Log(a); // => 1
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record A(int N) : Shape;
public record B(int N) : Shape;
public record C(int N) : Shape;
public class UnThreeCases : TsukimiBehaviour
{
void Start()
{
Shape s = new A(1);
int v = s switch { A a => a.N, B b => b.N, C c => c.N, _ => 0 };
Debug.Log(v); // => 1
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnIsPattern : TsukimiBehaviour
{
void Start()
{
Shape s = new Circle(1f);
bool isCircle = s is Circle;
Debug.Log(isCircle); // => true
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnParameter : TsukimiBehaviour
{
void Start()
{
Use(new Circle(1f));
}
private void Use(Shape s)
{
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
_ => 0f,
};
Debug.Log(a); // => 1
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnReturnValue : TsukimiBehaviour
{
void Start()
{
Shape s = Make();
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
_ => 0f,
};
Debug.Log(a); // => 1
}
private Shape Make()
{
return new Circle(1f);
}
}
using UnityEngine;
using Tsukimi;
public abstract record Shape;
public record Circle(float R) : Shape;
public record Rect(float W, float H) : Shape;
public class UnArray : TsukimiBehaviour
{
void Start()
{
Shape[] all = new Shape[2];
all[0] = new Circle(1f);
all[1] = new Rect(1f, 2f);
float total = 0f;
for (int i = 0; i < all.Length; i++)
{
Shape s = all[i];
float a = s switch
{
Circle c => c.R,
Rect r => r.W * r.H,
_ => 0f,
};
total += a;
}
Debug.Log(total); // => 3
}
}