Types2 min read

Enums

Algebraic data types with variants, pattern matching, and compile-time methods.

Reading Time
2 min
Word Count
197
Sections
10
Try It Live

Turn the guide into code

Take the key idea from this page into the playground and validate it in a real shader instead of leaving it as theory.

Open Playground

BWSL enums cover both plain named values and payload-carrying sum types. They also support eval methods and bitflag-style usage.

Basic Enums

At their simplest, enums define a set of named variants:

bwsl
enum RenderMode {
Forward,
Deferred,
RayTraced
}

Variants with Associated Data

Enum variants can carry associated data:

bwsl
enum SDFShape {
Sphere(float radius),
Box(float3 size),
Torus(float major, float minor)
}
SDFShape sphere = SDFShape::Sphere(1.0);
SDFShape box = SDFShape::Box(float3(1.0, 2.0, 1.0));
SDFShape torus = SDFShape::Torus(2.0, 0.5);

Eval Methods

Enums can define eval methods that pattern match on the current variant. The parameter list does not declare self; self is implicit inside the body.

bwsl
enum SDFShape {
Sphere(float radius),
Box(float3 size),
Torus(float major, float minor),
eval distance :: (float3 p) -> float {
Sphere(r): length(p) - r
Box(size): {
float3 d = abs(p) - size;
float outside = length(max(d, 0.0));
float inside = min(max(d.x, max(d.y, d.z)), 0.0);
return outside + inside;
}
Torus(major, minor): {
float2 q = float2(length(p.xz) - major, p.y);
return length(q) - minor;
}
}
eval normal :: (float3 p, float eps) -> float3 {
float d = self.distance(p);
return normalize(float3(
self.distance(p + float3(eps, 0.0, 0.0)) - d,
self.distance(p + float3(0.0, eps, 0.0)) - d,
self.distance(p + float3(0.0, 0.0, eps)) - d
));
}
}

Method Syntax

  • eval marks the method for compile-time evaluation
  • self refers to the enum instance and is available implicitly
  • Pattern arms use VariantName(bindings): expression syntax
  • Multi-statement arms use braces: VariantName(bindings): { ... }

Pattern Matching in Functions

Pattern matching also works outside enum definitions:

bwsl
shapeDistance :: (SDFShape shape, float3 p) -> float {
Sphere(r): length(p) - r
Box(size): {
float3 d = abs(p) - size;
return length(max(d, 0.0));
}
Torus(major, minor): {
float2 q = float2(length(p.xz) - major, p.y);
return length(q) - minor;
}
}

Default Arms

Use default to handle multiple variants with a single arm:

bwsl
enum ShaderValue {
Constant(float4),
Generated,
Computed,
eval isStatic :: () -> bool {
Constant(_): true
default: false
}
}

The _ wildcard ignores the associated data.

Typed Enums and Bitflags

Enums can specify an underlying integer type and explicit values:

bwsl
enum Channels : uint {
Red = 0b0001,
Green = 0b0010,
Blue = 0b0100,
Alpha = 0b1000,
eval has :: (Channels flag) -> bool {
return (self & flag) != 0;
}
}
Channels mask = Channels::Red | Channels::Blue;
bool hasRed = mask.has(Channels::Red);

Supported Underlying Types

TypeDescription
intSigned integer-backed enum
uintUnsigned integer-backed enum

Complex Example

bwsl
enum Light {
Point(float3 position, float radius),
Directional(float3 direction),
eval directionTo :: (float3 surfacePos) -> float3 {
Point(pos, _): normalize(pos - surfacePos)
Directional(dir): -dir
}
eval intensityAt :: (float3 surfacePos) -> float {
Point(pos, radius): {
float dist = distance(pos, surfacePos);
return saturate(1.0 - dist / radius);
}
Directional(_): 1.0
}
}

When the enum variant is known at compile time, eval methods are fully evaluated and inlined, resulting in zero runtime overhead.

See Also