#Better way of pattern matching

1 messages · Page 1 of 1 (latest)

obsidian rampart
#

Hey guys, I'm trying to figure out tagged enums, here are my types

const std = @import("std");

const CollisionDetectorType = enum {
    rectangle,
    circle,
    triangle,
};

pub const Rectangle = struct {
    width: f16,
    height: f16,

    fn getArea(self: *Rectangle) f32 {
        return self.width * self.height;
    }
};

const Circle = struct {
    radius: f16,

    fn getArea(self: *Circle) f32 {
        return std.math.pi * self.radius * self.radius;
    }
};

const Triangle = struct {
    height: u16,
    base: u16,

    fn getArea(self: *Triangle) f32 {
        return self.height * self.base / 2;
    }
};

pub const CollisionDetector = union(CollisionDetectorType) {
    rectangle: Rectangle,
    circle: Circle,
    triangle: Triangle,
};

and here is how I create these structs and use them

    const rectDetector = CollisionDetectorTypes.CollisionDetector{ .rectangle = .{ .width = 20, .height = 20 } };
    const circleDetector = CollisionDetectorTypes.CollisionDetector{ .circle = .{ .radius = 15 } };
        switch (rectDetector) {
            .rectangle => |rect| {
                raylib.drawRectangle(300, 400, rect.width, rect.height, raylib.Color.blue);
            },
            else => unreachable,
        }

        switch (circleDetector) {
            .circle => |circle| {
                raylib.drawCircle(400, 400, circle.radius, raylib.Color.red);
            },
            else => unreachable,
        }

I'm pretty sure I'm doing something wrong, because there is no way that I have to switch all of my collision structs to know if they are rectangle or circle even though I just passed either rectangle or circle to them. What is the correct way of doing this pattern match so it isn't so extensive?

jolly oracle
#

what exactly are you trying to do in the second snippet? it's kinda hard to understand...

#

also, unrelated, consider changing```zig
const CollisionDetectorType = enum {
rectangle,
circle,
triangle,
};

pub const CollisionDetector = union(CollisionDetectorType) {
rectangle: Rectangle,
circle: Circle,
triangle: Triangle,
};
intozig
pub const CollisionDetector = union(enum) {
rectangle: Rectangle,
circle: Circle,
triangle: Triangle,
};

you can ask Zig to create the tag `enum` for you
obsidian rampart
#

ah ok, nice, in the second snippet I cut some code because I thought it was not needed for the question, basically I'm trying to draw my structs on the screen, but why can I not just use rectDetector.width? I have to pattern match it to the rectangle type and then use it even though I created it as a rectangle and a circle respectively.

#

Here is the full main code for now, still trying to draw stuff on the screen

#
const CollisionDetectorTypes = @import("collision_detector.zig");
const raylib = @import("raylib");
const std = @import("std");

pub fn main() !void {
    const screenWidth: comptime_int = 800;
    const screenHeight: comptime_int = 600;
    const rectDetector = CollisionDetectorTypes.CollisionDetector{ .rectangle = .{ .x = 300, .y = 400, .width = 20, .height = 20 } };
    const circleDetector = CollisionDetectorTypes.CollisionDetector{ .circle = .{ .x = 400, .y = 400, .radius = 15 } };

    raylib.initWindow(screenWidth, screenHeight, "Invaders");
    defer raylib.closeWindow();

    raylib.setTargetFPS(60);

    while (!raylib.windowShouldClose()) {
        raylib.beginDrawing();
        defer raylib.endDrawing();

        raylib.clearBackground(raylib.Color.black);

        raylib.drawText("Game", 300, 250, 40, raylib.Color.purple);

        switch (rectDetector) {
            .rectangle => |rect| {
                raylib.drawRectangle(rect.x, rect.y, rect.width, rect.height, raylib.Color.blue); 
            },
            else => unreachable,
        }

        switch (circleDetector) {
            .circle => |circle| {
                raylib.drawCircle(400, 400, circle.radius, raylib.Color.red);
            },
            else => unreachable,
        }
    }
}
jolly oracle
# obsidian rampart ah ok, nice, in the second snippet I cut some code because I thought it was not ...

I have to pattern match it to the rectangle type and then use it even though I created it as a rectangle and a circle respectively.
indeed you've initialised your rectDetector as the rectangle variant, but after wrapping it in a CollisionDetector Zig "forgets" that information - as far as the language is concerned, you just got yourself a CollisionDetector which may be a rectangle, or circle, or anything else.

in this case, I don't really see a reason to wrap your rectangle in a CollisionDetector to begin with - just keep it a Rectangle

obsidian rampart
#

Right, I'm still thinking with a OOP mindset, I'm thinking of the CollisionDetector type as an interface, because the other structs have the same method getArea

#

Another unrelated question, is there a way to unwrap my types from my collision detector file? because I have to always use CollisionDetectorTypes.MyType is there a way to unwrap it so I can just use MyType?

jolly oracle