Algae: Examples

Variants

Variants are like your own custom enums, except that they can contain another value. Let’s take a look at what that means, exactly.

We want to create a couple of related variants at the same time, so we’ll use the map function:

-- src/client/inputTypes.lua

local InputTypes = Algae.map({
    -- doesn't need any extra data, so we pass an empty table
    MouseClicked = {},

    -- needs to know which key was pressed
    KeyPressed = function(key)
        return { key = key }
    end,
})

Now let’s use them. For the sake of this example, assume that we’re storing the last input command in a table somewhere named state.

local inputTypes = require(ReplicatedStorage.Client.InputTypes)

local state = ... -- somewhere in the depths of our codebase

UserInputService.InputBegan:Connect(function(inputObject, gameProcessed)
    -- something else is using this input, abort!
    if gameProcessed then
        return
    end
    
    -- when the user presses a key on their keyboard
    if inputObject.UserInputType == Enum.UserInputType.Keyboard then
        -- call the function we created for KeyPressed in our map & pass it the keycode
        state.lastProcessedCommand = inputTypes.KeyPressed(inputObject.KeyCode)
    -- when the user presses the left mouse button
    elseif inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
        state.lastProcessedCommand = inputTypes.MouseClicked
    end
end)

This is pretty cool already, but let’s take it to the next level.

Matching

Continuing with our example, let’s actually do something with our state when it changes. When lastProcessedCommand isn’t nil, we’ll print a message depending on what it is. Once that’s done, we’ll clear the value from our state.

We can do this easily with match:

local state = ...

RunService.Heartbeat:Connect(function()
    -- inputProcessed will become whatever is returned from the case that is matched.
    -- you don't always need to use the return value, but it can be pretty handy!
    local inputProcessed = Algae.match(state.lastProcessedCommand, {
        MouseClicked = function()
            print("The mouse has been clicked!")
            return true
        end,
        KeyPressed = function(data)
            -- `data` is the value we returned from the function we mapped to KeyPressed
            print(data.key .. " has been pressed!")
            return true
        end,
        -- the `_` case is the default case
        -- the default case is used when the value doesn't match any of the other cases
        _ = function()
            -- we can't do anything with this value, so return false
            return false
        end,
    })
    
    if inputProcessed then
        print("Clearing the previous command")
        state.lastProcessedCommand = nil
    end
end)

match can also accept regular enums from Roblox as well. We could technically replace the if/elseif statement in the first example with a match if we wanted to!

All in all, Algae is a nice tool if you want to use it. It’s not going to make your code 10x more efficient (you won’t see any performance loss, either), but it will make your life a bit easier when you feel like you’ve got a good use case for it. In my current project, I’m using it to map different kinds of user input to commands that can be processed by my game. It makes it easy for me to support multiple input devices when the raw input is filtered through a couple match functions into something that doesn’t care whether a player is using a mouse or a touch screen.