Skip to content

API Reference

Disclaimer: These are not the official docs and the new functions are not available for use. It would be nice if someone helped me add them though.

Types

Array

type Array<Value> = {[number]: Value}

A table with values of type Value and numeric keys 1..n with no gaps


Args

type Args<Value> = {[number]: Value}

A table with values of type Value and numeric keys, possibly with gaps.


Map

Map<Key, Value> = {[Key]: Value}

A table with keys of type Key and values of type Value


Set

type Set<Key> = {[Key]: boolean}

A table with keys of a fixed type Key and a boolean value representing membership of the set (default is false)


Table

type Table = {[any]: any}

A table of any type


Class

type Class<Object> = {

new: () -> Object
}

A class has a constructor returning an instance of Object type


Handlers

Some functions such as filter will require handlers. There will be a Key and Value type to denote whether the key or value argument is passed first, but they are both any type unless otherwise specified.


AnyFunction

type AnyFunction = (...any) -> any

Represents a function which takes any arguments and returns any value


Tables

These utilities operate on Tables of any kind.


all

Tables

type AllHandler = (Value, Key) -> boolean

all(input: types.Table, handler: AllHandler?): boolean

Iterates through all elements of the input Table.

Calls the handler for each entry and returns false if the handler returns falsy for any element which it is called with. Otherwise, all elements were truthy so return true.

If the handler is not provided, use the truthiness of the values in the table.

Examples

-- These are the only falsy values in Lua
Dash.all({nil, false}) --> false
Dash.all({true, 0, "0"}) --> true
-- Do all words start with 'ro'?
Dash.all(
    {"roblox", "roact", "rodux"},
    function(word) return Dash.startsWith(word, "ro")
end)
--[[
Output: true
]]


collect

Tables

type CollectHandler = (Key, Value) -> (any, any)?

collect(input: Types.Table, handler: CollectHandler): Types.Map<any, any>

Collect returns a new Table derived from input by iterating through its pairs and calling the handler on each (key, value) tuple.

The handler should return a new (newKey, value) tuple to be inserted into the returned Table, or nil if no value should be added.

Example

-- Invert keys and values of a table
Dash.collect({a = "1", b = "2", c = 3}, function(key, value)
    return value, key
end)

--[[
Output: {
    [3] = "c"
    ["1"] = "a",
    ["2"] = "b",
}
]]

collectArray

Tables

type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?

collectArray<Key, Value, NewValue>(input: { [Key]: Value }, handler: CollectHandler<Key, Value, NewValue>): { NewValue }

Collect returns a new array derived from input by iterating through its pairs and calling the handler on each (key, value) tuple.

The handler should return a new value to be pushed onto the end of the result array, or nil if no value should be added.

Example

-- Double all elements, ignoring results that are multiples of three
Dash.collectArray({1, 2, 3, 4, 5, 6}, function(key, value)
    local newValue = value * 2
    return if newValue % 3 == 0 then nil else newValue
end)

--[[
Output: {
[1] = 2,
[2] = 4,
[3] = 8,
[4] = 10
}
]]

collectSet

Tables

type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?

collectSet<Key, Value, NewValue>(
    input: { [Key]: Value },
    handler: CollectHandler<Key, Value, NewValue>?
): Types.Set<Value | NewValue>

Build a set from the entries of the input Table, calling handler on each entry and using the returned value as an element to add to the set.

If handler is not provided, values of input are used as elements.


Examples

-- Convert array to Set
Dash.collectSet({"toast", "bagel", "donut"})

--[[
Output: {
    ["bagel"] = true,
    ["donut"] = true,
    ["toast"] = true
}
]]
-- Create set of first letters of each word
Dash.collectSet({"toast", "bagel", "donut", "bread"}, function(key, value)
    return value:sub(1, 1)
end)

--[[
Output: {
    ["b"] = true,
    ["d"] = true,
    ["t"] = true
}
]]

copy

Tables

copy(input: Types.Table): Types.Table

Returns a shallow copy of the input Table.

Example

Dash.copy({a = 1, b = 3})

--[[
Output: {
    ["a"] = 1,
    ["b"] = 3
}
]]

count

Tables

type CountHandler<Key, Value> = (Value, Key) -> boolean

count<Key, Value>(input: { [Key]: Value }, handler: CountHandler<Key, Value>?): number

If no handler is provided, return the number of elements in the input Table.

If the handler is provided, increase the count for each element for which the handler returns true on the (value, key) pair.

Examples

Dash.count({1, 2, 3, 4, 5}) --> 5
-- Count the number of ids that start with 1
Dash.count(
    {[12] = true, [24] = true, [153] = true, [199] = true},
    function(value, id) return tostring(id):sub(1, 1) == "1"
end)

--[[
Output: 3
]]
-- Count the number of numbers divisible by 5
Dash.count(
    {1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
    function(num) return num % 5 == 0
end)

--[[
Output: 2
]]

filter

Tables

type FilterHandler<Key, Value> = (Value, Key) -> boolean

filter<Key, Value>(input: { [Key]: Value }, handler: FilterHandler<Key, Value>): { Value }

Filter the input Table by calling the handler on each (value, key) tuple.

For an array input, the order of elements is preserved in the output.

The handler should return truthy to preserve the value in the resulting Table.

Example

-- Take only the elements whose values begin with "r"
Dash.filter(
    {place = "roblox", packages = "rotriever", ide = "studio"},
    function(word) return Dash.startsWith(word, "r")
end)

--[[
Output: {
    [1] = "roblox",
    [2] = "rotriever"
}
]]

find

Tables

type FindHandler<Key, Value> = (Value, Key) -> boolean

find<Key, Value>(input: { [Key]: Value }, handler: FindHandler<Key, Value>): Value?

Returns an element in the input Table that the handler returns true for, when passed the (value, key) entry.

Returns nil if no entries satisfy the condition.

For an array, this first matching element is returned. For a Map, an arbitrary matching element is returned if it exists.

Examples

-- Check if there's the "ExtraSettings" key and get the value of that key if so
Dash.find(
    {Id = 145, IsReady = false, ExtraSettings = {AutoReady = true}},
    function(value, key) return key == "ExtraSettings" end
)

--[[
Output: {
    ["AutoReady"] = true
}
]]


Dash.find({Id = 145, IsReady = false},
    function(value, key) return key == "ExtraSettings" end
)
--[[
Output: nil
]]


forEach

Tables

type ForEachHandler<Key, Value> = (Value, Key) -> ()

forEach<Key, Value>(input: { [Key]: Value }, handler: ForEachHandler<Key, Value>)

Iterates through the elements of the input Table.

If the table is an array, it iterates in order 1..n.

If the table is a Map, the keys are visited in an arbitrary order.

Calls the handler for each entry.

Example

-- Print all values of table
Dash.forEach({"Item 1", "Item 2", "Item 3"}, function(value) print(value) end)

--[[
Output: Item 1
Item 2
Item 3
]]

frequencies

Tables

type FrequenciesHandler<Key, Value, NewKey> = (Value, Key) -> NewKey

frequencies<Key, Value, NewKey>(
    input: { [Key]: Value },
    handler: FrequenciesHandler<Key, Value, NewKey>?
): { [NewKey | Value]: number }

If no handler is provided, returns a Map with keys as unique values of the input Table and values as the count of each value.

If a handler is provided, returns a Map with keys as unique elements given by the handler and values as the count of each mapped key.

Examples

Dash.frequencies({"Red", "Black", "Orange", "Red"})

--[[
Output:{
    ["Black"] = 1,
    ["Orange"] = 1,
    ["Red"] = 2
}
]]
-- Count colors by simple definition of neutral and non-neutral
function toNeutral(color)
    return if Dash.includes({"Black", "Gray", "White"}, color)
        then "Neutral"
        else "Non-neutral"
end
Dash.frequencies(
    {"Black", "Orange", "Blue", "Gray", "White"},
    function(color) return toNeutral(color)
end)

--[[
Output: {
    ["Neutral"] = 3,
    ["Non-neutral"] = 2
}
]]

groupBy

Tables

type GroupByHandler<Key, Value, GroupKey> = (Value, Key) -> GroupKey

groupBy<Key, Value, GroupKey>(
    input: { [Key]: Value },
    getKey: GroupByHandler<Key, Value, GroupKey> | GroupKey
): { [GroupKey]: { Value } }

Groups values in the input Table by their getKey value.

Each value of the result Table is an array of values from the input Table which were assigned the corresponding key.

If getKey is a function, it is called with each (value, key) entry and uses the return value as the corresponding key to insert at in the result Table. Otherwise, the getKey value is used directly as the key itself.

Example

local output = groupBy({
    bike = {
        name = "bike",
        color = "blue"
    },
    car = {
        name = "car",
        color = "red"
    },
    van = {
        name = "van",
        color = "white"
    },
    ghost = {
        name = "ghost"
    }
}, "color")
--[[
Output: {
    blue = {
        {
            color = "blue",
            name = "bike"
        }
    },
    red = {
        {
            color = "red",
            name = "car"
        }
    },
    white = {
        {
            color = "white",
            name = "van"
        }
    }
}
]]

includes

Tables

includes(source: Types.Table, value: any): boolean

Returns true if the item exists as a value in the source Table.

Example

-- Does the table include 100?
Dash.includes({1, 10, 100, 1000}, 100)

--[[
Output: true
]]

See

For a stronger version of Dash.includes, use Dash.some.


keyBy

Tables

type KeyByHandler<Key, Value, NewKey> = (Value, Key) -> NewKey

keyBy<Key, Value, NewKey>(input: { [Key]: Value }, getKey: KeyByHandler<Key, Value, NewKey> | NewKey): { [NewKey]: Value }

Assigns values in the input Table by their getKey value.

If getKey is a function, it is called with each (value, key) entry and uses the return value as the corresponding key to assign to in the result Table. Otherwise, the getKey value is used directly as the key itself.

Example

local output = keyBy({
    bike = {
        name = "bike",
        color = "blue"
    },
    car = {
        name = "car",
        color = "red"
    },
    van = {
        name = "van",
        color = "white"
    },
    ghost = {
        name = "ghost"
    }
}, "color")
[[
Output: {
    blue = {
        color = "blue",
        name = "bike"
    },
    red = {
        color = "red",
        name = "car"
    },
    white = {
        color = "white",
        name = "van"
    }
}]]

keys

Tables

keys<Key, Value>(input: { [Key]: Value }): { Key }

Returns an array of the keys in the input Table.

If the input is an array, ordering is preserved.

If the input is a Map, elements are keys in an arbitrary order.

Example:

Dash.keys({
    Color = "Purple",
    Type = "Fruit",
    Shape = "Round"
})

--[[
Output: {
    [1] = "Color",
    [2] = "Type",
    [3] = "Shape"
}
]]

map

Tables

type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue

map<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>): { [Key]: NewValue }

Iterates through the elements of the input Table.

For an array input, the elements are visited in order 1..n.

For a Map input, the elements are visited in an arbitrary order.

Calls the handler for each entry and constructs a new Table using the same keys but replacing the values with new ones returned from the handler.

Values returned by handler must be defined.

Example

-- Map characters to their ASCII
Dash.map({"a", "b", "c"}, function(char) return string.byte(char) end)

--[[
Output: {
    [1] = 97,
    [2] = 98,
    [3] = 99
}
]]

See


mapOne

Arrays

type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue?

mapOne<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>?): NewValue?

Iterates through the elements of the input Table in no particular order.

Calls the handler for each entry and returns the first non-nil value returned by the handler. If all returned from the handler values are nil, nil is returned.

If handler is nil, the first value visited is returned.

Example

-- Get any message that's not hidden and return its id.
Dash.mapOne({
    {Id = 1, IsHidden = true},
    {Id = 3, IsHidden = false},
    {Id = 2, IsHidden = false},
}, function(message)
    return if message.IsHidden then nil else message.Id
end)

--[[
Output: 3
]]

max

Tables

type MaxComparator = (any, any) -> boolean
type MaxHandler = (Value, Key) -> any

max(input: Types.Table, handler: MaxHandler?, comparator: MaxComparator): any

Returns the maximum value in the input Table. By default, this returns the greatest value in the table as defined by the > operator.

If a handler is provided, elements will first be transformed by handler(value, key) before being used for comparison.

Elements will be compared using the comparator if it is provided. The comparator should take two elements and return true if the first one is greater than the second one, and false otherwise.

If the provided input has no elements, return nil.

Examples

Dash.max({1, 2, 3}) --> 3
Dash.max({"1", "2", "10"}) --> "2"
Dash.max({1, 2, 3}, function(num) return -num end) --> 1
Dash.max(
    {"blue", "red", "orange"},
    nil,
    function(word1, word2) return word1:len() > word2:len() end
) --> "orange"

memoize

Functions

type ResolverFunction = (...any) -> string

memoize(func: Types.AnyFunction, resolver: ResolverFunction?): Types.AnyFunction

Creates a function that memoizes the result of func. The memoized function will cache results based on the arguments provided. If a resolver function is provided, it will be used to generate the cache key from the arguments.

Examples

local function add(a, b)
    return a + b
end

local memoizedAdd = memoize(add)
print(memoizedAdd(1, 2)) -- Calculates and caches: 3
print(memoizedAdd(1, 2)) -- Returns from cache: 3

-- With custom resolver
local memoizedWithResolver = memoize(add, function(a, b)
    return string.format("%d_%d", a, b)
end)

Usage

  • Use memoization for expensive computations that are called frequently with the same arguments
  • The resolver function can be used to customize how arguments are used to generate cache keys
  • Be mindful of memory usage as cached results are stored indefinitely

min

Table

type MinComparator = (any, any) -> boolean
type MinHandler = (Value, Key) -> any

min(input: Types.Table, handler: MinHandler?, comparator: MinComparator): any

Returns the minimum value in the input Table. By default, this returns the least value in the table as defined by the < operator.

If a handler is provided, elements will first be transformed by handler(value, key) before being used for comparison.

Elements will be compared using the comparator if it is provided. The comparator should take two elements and return true if the first one is less than the second one, and false otherwise.

If the provided input has no elements, return nil.

Examples

Dash.min({1, 2, 3}) --> 1
Dash.min({"2", "20", "10"}) --> "10"
Dash.min({3, 2, 1}, function(num) return -num end) --> 3
Dash.min(
    {"blue", "red", "orange"},
    nil,
    function(word1, word2) return word1:len() < word2:len() end
) --> "red"

omit

Tables

omit<Key, Value>(input: { [Key]: Value }, keys: { Key }): { [Key]: Value }

Return a new Table made from entries in the input Table whose key is not in the keys array.

If the input is an array, ordering is preserved.

If the input is a Map, elements are returned in an arbitrary order.

Example

-- Remove the ShouldShow key/value pair from the table
Dash.omit({
    ShouldShow = true,
    Text = "Hello World!",
    Title = "Greetings!",
}, {"ShouldShow"})

--[[
Output: {
    ["Text"] = "Hello World!",
    ["Title"] = "Greetings!"
}
]]

pick

Tables

type PickHandler<Key, Value> = (Value, Key) -> boolean

pick<Key, Value>(input: { [Key]: Value }, handler: PickHandler<Key, Value>): { [Key]: Value }

Pick entries in the input Table which should remain in the output by calling the handler on each (child, index) tuple.

The handler should return truthy to preserve the value in the resulting Table.

Examples

Dash.pick(
    {10, 20, 30, 40, 50, 60},
    function(value, _) return value % 20 == 0 end
)

--[[
Output: {
    [2] = 20,
    [4] = 40,
    [6] = 60
}
]]

reduce

Tables

type ReduceHandler<Key, Value, Accumulator> = (Accumulator, Value, Key) -> Accumulator

reduce<Key, Value, Accumulator>(
    input: { [Key]: Value },
    handler: ReduceHandler<Key, Value, Accumulator>,
    initial: Accumulator
): Accumulator

Iterate through the elements of the input Table, preserving order if it is an array.

Call the handler for each element, passing the return of the previous call as the first argument.

The initial value is passed into the first call, and the final value returned by the function.

Examples

-- Count occurences of each element in array and output a table of counts
-- See Dash.frequencies
Dash.reduce(
    {"Red", "Black", "Red", "Red", "Black"},
    function(acc, color)
        if acc[color] == nil then
            acc[color] = 1
        else
            acc[color] += 1
        end
        return acc
    end, {}
)

--[[
Output: {
    ["Black"] = 2,
    ["Red"] = 3
}
]]
-- Sum up elements, doubling even indices and halving odd indices
-- Expected: 0.5 + 4 + 1.5 + 8 + 2.5 = 16.5
Dash.reduce(
    {1, 2, 3, 4, 5},
    function(acc, num, index)
        return acc + if index % 2 == 0 then num * 2 else num / 2
    end, 0
)
--[[
Output: 16.5
]]

shallowEqual

Tables

shallowEqual(left: any, right: any): boolean

Returns true if the left and right values are equal (by the equality operator) or the inputs are tables, and all their keys are equal.

Examples

Dash.shallowEqual({
    A = 1,
    B = 2
}, {
    A = 1,
    B = 2,
})

--[[
Output: true
]]
Dash.shallowEqual({
    A = 1,
    B = 2,
    C = 3
}, {
    A = 1,
    B = 2,
    D = 3
})

--[[
Output: false
]]

some

Tables

type SomeHandler<Key, Value> = (Value, Key) -> boolean

some<Key, Value>(input: { [Key]: Value }, handler: SomeHandler<Key, Value>): boolean

Iterates through the elements of the input Table in no particular order.

Calls the handler for each entry and returns true if the handler returns truthy for any element which it is called with.

Example

-- Does there exist a red fruit?
Dash.some(
    {
        {Type = "Cherry", Color = "Red"},
        {Type = "Strawberry", Color = "Red"},
        {Type = "Blueberry", Color = "Blue"}
    },
    function(fruit) return fruit.Color == "Red" end
)

--[[
Output: true
]]

values

Tables

values<Key, Value>(input: { [Key]: Value }): { Value }

Returns an array of the values in the input Table.

If the input is an array, ordering is preserved.

If the input is a Map, values are returned in an arbitrary order.

Example

Dash.values({
    Type = "Cherry",
    Color = "Red",
    Price = "Expensive",
    EnjoymentLevel = "High"
})

--[[
Output: {
    [1] = "Red",
    [2] = "Cherry",
    [3] = "High",
    [4] = "Expensive"
}
]]

Arrays

These utilities operate on arrays, tables with ordered keys 1..n.


append

Mutable | Arrays

append<T>(target: { T }, ...: { T }): { T }

Adds new elements to the target array from subsequent array arguments in left-to-right order.

Arguments which are nil or None are skipped.

Example

Dash.append({1, 2}, {3, 4}, {5})

--[[
Output: {
    [1] = 1,
    [2] = 2,
    [3] = 3,
    [4] = 4,
    [5] = 5
}
]]

findIndex

Arrays

type FindHandler<Value> = (Value, number) -> boolean

findIndex<Value>(input: { Value }, handler: FindHandler<Value>): number?

Returns the index of the first element in the input array that the handler returns true for, when passed the (value, key) entry.

Returns nil if no entries satisfy the condition.

Examples

-- Find index of "Clementine" fruit if it exists in the array
Dash.findIndex(
    {"Apple", "Banana", "Clementine"},
    function(fruit) return fruit == "Clementine" end
)

--[[
Output: 3
]]
Dash.findIndex(
    {"Apple", "Banana"},
    function(fruit) return fruit == "Clementine" end
)

--[[
Output: nil
]]

flat

Arrays

flat(input: { any }): { any }

Flattens the input array by a single level. Outputs a new array of elements merged from the input array arguments in left-to-right order.

Example

-- Flatten a partition of numbers in the range 1-5
Dash.flat({
    {1, 2, 3},
    {4, 5}
})

--[[
Output:  {
    [1] = 1,
    [2] = 2,
    [3] = 3,
    [4] = 4,
    [5] = 5
}
]]

last

Arrays

type FindHandler<Value> = (Value, number) -> boolean

last<Value>(input: { Value }, handler: FindHandler<Value>?): Value?

Returns the last element in the input array that the handler returns true for, when passed the (value, key) entry.

Returns nil if no entries satisfy the condition.

If handler is not defined, the function simply returns the last element of the array.

Examples

Dash.last({3, 2, 1})

--[[
Output: 1
]]
-- Get last odd number
Dash.last({4, 3, 2}, function(num) return num % 2 == 1 end)

--[[
Output: 3
]]

mapFirst

Arrays

type MapHandler<Value, NewValue> = (Value, number) -> NewValue?

mapFirst<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?

Iterates through the elements of the input array in order 1..n.

Calls the handler for each entry and returns the first non-nil value returned by the handler. If all returned from the handler values are nil, nil is returned.

Example

-- Get first color that's 6 letters and return its first letter
Dash.mapFirst(
    {"Red", "Yellow", "Orange", "Blue"},
    function(color)
        return if color:len() == 6 then color:sub(1, 1) else nil
    end
)

--[[
Output: Y
]]

mapLast

Arrays

type MapHandler<Value, NewValue> = (Value, number) -> NewValue?

mapLast<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?

Iterates through the elements of the input array in reverse in order n..1.

Calls the handler for each entry and returns the first non-nil value returned by the handler. If all returned from the handler values are nil, nil is returned.

Example

-- Get last color that's 6 letters and return its first letter
Dash.mapLast(
    {"Red", "Yellow", "Orange", "Blue"},
    function(color)
        return if color:len() == 6 then color:sub(1, 1) else nil
    end
)

--[[
Output: O
]]

product

Arrays

product(input: { number }): number

Multiplies together all the numbers in the input array.

If the input has no elements, return 1.

Example

Dash.product({3, 3, 2}) --> 18

reverse

Arrays

reverse<T>(input: { T }): { T }

Reverse the order of the elements in the input array.

Example

Dash.reverse({3, 2, 1})

--[[
Output: {
    [1] = 1,
    [2] = 2,
    [3] = 3
}
]]

slice

Arrays

slice<T>(input: { T }, left: number?, right: number?): { T }

Return a portion of the input array starting with the element at the left index and ending with the element at the right index (i.e. an inclusive range)

If left is not defined, it defaults to 1. If right is not defined, it defaults to the length of the array (i.e. the last element)

If left is -n, the slice starts with the element n places from the last one. If right is -n, the slice ends with the element n places from the last one.

An empty array is returned if the slice has no or negative length.

Examples

Dash.slice({1, 2, 3, 4, 5}, 2, 4)

--[[
Output: {
    [1] = 2,
    [2] = 3,
    [3] = 4
}
]]
Dash.slice({1, 2, 3, 4, 5}, 3)

--[[
Output: {
    [1] = 3,
    [2] = 4,
    [3] = 5
}
]]
Dash.slice({1, 2, 3, 4, 5}, nil, -1)

--[[
Output: {
    [1] = 1,
    [2] = 2,
    [3] = 3,
    [4] = 4
}
]]

sum

Arrays

sum(input: { number }): number

Adds together all the numbers in the input array.

If the input array has no elements, return 0.

Example

Dash.sum({3, 2, 1}) --> 6

Maps

These utilities operate on Maps, tables with arbitrary keys.


assign

Mutable | Maps

assign<Key, Value>(target: Types.Map<Key, Value>, ...: Types.Map<Key, Value>): Types.Map<Key, Value>

Adds new values to target from subsequent Table arguments in left-to-right order.

Examples

local characters = {
    Frodo = {
        name = "Frodo Baggins",
        team = "blue"
    },
    Boromir = {
        score = 5
    }
}
local otherCharacters = {
    Frodo = {
        team = "red",
        score = 10
    },
    Bilbo = {
        team = "yellow",
    },
    Boromir = {
        score = {1, 2, 3}
    }
}
local result = assign(characters, otherCharacters)
print(result) --[[
--> {
    Frodo = {
        team = "red",
        score = 10
    },
    Bilbo = {
        team = "yellow"
    },
    Boromir = {
        score = {1, 2, 3}
    }
}
]]

See


freeze

Maps

freeze(objectName: string, object: Types.Table, throwIfMissing: boolean?): Types.Table

Returns a new read-only view of object which prevents any values from being changed.

Parameters

Name Description
name The name of the object for improved error message readability.
throwIfMissing If true then access to a missing key will also throw.

Notes

Unfortunately you cannot iterate using pairs or ipairs on frozen objects because Luau doesn't support defining these custom iterators in metatables.

Example

local drink = freeze("Ice Cream", {
    flavor = "mint",
    topping = "sprinkles"
}, true)
print(drink.flavor) --> "mint"
drink.flavor = "vanilla"
--!> ReadonlyKey: Attempt to write to readonly key "flavor" (a string) of frozen object "Ice Cream"
print(drink.syrup) --> nil
--!> MissingKey: Attempt to read missing key "syrup" (a string) of frozen object "Ice Cream"

get

Tables

get<T>(object: { [any]: any }, path: { any }, defaultValue: T?): T?

Gets the value at path of object. If the resolved value is nil, the defaultValue is returned in its place.

The path should be an array of keys (e.g. { "a", "b", "c" }, { "test", "test.test", 0 }).

Examples

local object = {
    a = {
        b = {
            c = 3
        }
    }
}
Dash.get(object, { "a", "b", "c" }) --> 3
Dash.get(object, { "x", "y", "z" }, "default") --> "default"
-- Array indexing
local object = {
    items = {
        { name = "first" },
        { name = "second" }
    }
}
Dash.get(object, { "items", 1, "name" }) --> "first"
-- Keys with dots
local object = {
    test = {
        ["test.test"] = {
            [0] = "value"
        }
    }
}
Dash.get(object, { "test", "test.test", 0 }) --> "value"

See - Dash.getOrSet - for getting a value with a default generator function


getOrSet

Maps

type GetValueHandler<Key, Value> = ({ [Key]: Value }, Key) -> Value

getOrSet<Key, Value>(input: { [Key]: Value }, key: Key, getValue: GetValueHandler<Key, Value>): Value

Returns a value of the input Table at the key provided. If the key is missing, the value is acquired from the getValue handler, added to the input Table and returned.

Examples

Dash.getOrSet(
    {Item = "Gummy Bear", Color = "Lime"},
    "Color",
    function() return "Yellow" end
)

--[[
Output: Lime
]]
Dash.getOrSet(
    {Item = "Gummy Bear"},
    "Color",
    function() return "Yellow" end
)

--[[
Output: Yellow
]]

join

Maps

join<Key, Value>(...: Types.Map<Key, Value>): Types.Map<Key, Value>

Output a new Map from merging all the keys in the Map arguments in left-to-right order.

Example

Dash.join(
    {Text = "Hello World!", Color = "Sky Blue"},
    {Title = "Greetings!", Color = "Indigo"}
)

--[[
Output: {
    ["Color"] = "Indigo",
    ["Text"] = "Hello World!",
    ["Title"] = "Greetings!"
}
]]

See


joinDeep

Maps

joinDeep(source: Types.Map<any, any>, delta: Types.Map<any, any>): Types.Map<any, any>

Creates a shallow clone of the source Map, and copies the values from the delta Map by key, like the join utility.

However, if any of the values are tables themselves, the joinDeep function is called recursively to produce a new table at the specified key.

The purpose of this function is to merge nested immutable data using as few table creation operations as possible, making it appropriate for updating state in a reducer.

Usage

  • The None symbol can be used to remove an existing value.

Example

local source = {
    name = "car",
    lights = {
        front = 2,
        back = 2,
        indicators = {
            color = "orange"
        },
        brake = {
            color = "red"
        }
    },
    tyres = 4
}
local delta = {
    name = "bike",
    lights = {
        front = 3,
        indicators = {
            rate = 20
        }
    },
    tyres = None
}
local output = joinDeep(source, delta)
[[
Output: {
    lights = {
        back = 2,
        brake = {
            color = "red"
        },
        front = 3,
        indicators = {
            color = "orange",
            rate = 20
        }
    },
    name = "bike"
}
]]

Strings


These utilities are helpful for working with strings.


endsWith

Strings

endsWith(input: string, suffix: string): boolean

Checks if input ends with the string suffix.

Examples

endsWith("Fun Roblox Games", "Games") --> true
endsWith("Bad Roblox Memes", "Games") --> false

isLowercase

Strings

isLowercase(input: string): boolean

Returns true if the first character of input is a lower-case character.

Throws if the input is not a string or it is the empty string.

Our current version of Lua unfortunately does not support upper or lower-case detection outside the english alphabet. This function has been implemented to return the expected result once this has been corrected.

Examples

Dash.isLowercase("abcdef") --> true
Dash.isLowercase("Title") --> false

isUppercase

Strings

isUppercase(input: string): boolean

Returns true if the first character of input is an upper-case character.

Throws if the input is not a string or it is the empty string.

Our current version of Lua unfortunately does not support upper or lower-case detection outside the english alphabet. This function has been implemented to return the expected result once this has been corrected.

Examples

Dash.isUppercase("ABCDEF") --> true
Dash.isUppercase("rObLoX") --> false

leftPad

Strings

leftPad(input: string, length: number, prefix: string?): string

Makes a string of length from input by repeating characters from prefix at the start of the string.

Params

  • prefix - default = ""

Examples

leftPad("toast", 6) --> " toast"
leftPad("2", 2, "0") --> "02"
leftPad("toast", 10, ":)") --> ":):):toast"

rightPad

Strings

rightPad(input: string, length: number, suffix: string?): string

Makes a string of length from input by repeating characters from suffix at the end of the string.

By default, suffix is " ".

Examples

rightPad("toast", 6) --> "toast "
rightPad("2", 2, "!") --> "2!"
rightPad("toast", 10, ":)") --> "toast:):):"

splitOn

Strings

splitOn(input: string, pattern: string): { string }

Splits input into parts based on a pattern delimiter and returns a Table of the parts, followed by a Table of the matched delimiters.

Example

local parts, delimeters = Dash.splitOn(
    "The quick brown fox jumps over the lazy dog",
    " "
)

print(parts)
--[[
Output: {
    [1] = "The",
    [2] = "quick",
    [3] = "brown",
    [4] = "fox",
    [5] = "jumps",
    [6] = "over",
    [7] = "the",
    [8] = "lazy",
    [9] = "dog"
}
]]

print(delimeters)
--[[
{
    [1] = " ",
    [2] = " ",
    [3] = " ",
    [4] = " ",
    [5] = " ",
    [6] = " ",
    [7] = " ",
    [8] = " "
}
]]

startsWith

Strings

startsWith(input: string, prefix: string): boolean

Checks if input starts with the string start.

Examples

startsWith("Fun Roblox Games", "Fun") --> true
startsWith("Chess", "Fun") --> false

trim

Strings

trim(input: string): string

Remove any whitespace at the start and end of the input string.

Example

Dash.trim("\n\t\rhello world   ") --> "hello world"

Functions

These utilities are helpful for working with functions.


compose

Functions

compose(...: { Types.AnyFunction }): Types.AnyFunction

Returns a function that calls the argument functions in left-right order on an input, passing the return of the previous function as argument(s) to the next.

Example

local function fry(item)
    return "fried " .. item
end
local function cheesify(item)
    return "cheesy " .. item
end
local prepare = compose(fry, cheesify)
prepare("nachos") --> "cheesy fried nachos"

forEachArgs

Functions

forEachArgs(handler: Types.AnyFunction, ...: Args<Value>): ()

Iterates through the tail arguments in order, including nil values up to the argument list length.

Calls the handler for each entry.


identity

Functions

identity(...)

The identity function, which simply returns its input parameters.

Can be used to make it clear that a handler returns its inputs.


isCallable

Functions

isCallable<T>(value: T): boolean

Returns true if the value can be called i.e. you can write value(...).


noop

Functions

noop()

A function which does nothing.

Can be used to make it clear that a handler has no function.


chain

Functions

chain("test":gmatch("t"), "test":gmatch("e"))

Returns a stateful iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterator, until all the iterators are exhausted.

Classes

These utilities are helpful for working with classes.


Error

Classes

Error.new(name: string, message: string, tags: Table?)

Create an error object with a specified name and message.

In native Lua, errors can only be string values. At Roblox, we can take advantage of throwing error objects to provide structured information about problems that occur.

The tags table stores rich information about an error which can be provided when it is thrown, and later passed to a logging endpoint.

Throwing an error instance captures its stack trace, avoiding the need to explicitly use xpcall.

Fields

Name Description
name: string The name of the error
message: string A message which will be formatted with Dash.format if the error is thrown
tags: Table A table to store custom rich information about the error
stack: string? The value of debug.traceback() when the error is thrown

Methods

Name Description
:joinTags(tags: Table?) Return a new error instance containing the tags provided joined to any existing tags of the current error instance.
:throw(tags: Table?) Throw an error.

The stack of the error is captured and stored.

If tags are provided, a new error is created and thrown with the joined tags of this instance.

Static Methods

Name Description
.new(name: string, message: string, tags: Table?) Returns a new Error instance
.is(other: any) Returns true if other is an Error instance

Usage

In general, errors should not be used during normal control flow.


Symbol

Classes

Create a symbol with a specified name. Upper snake-case is recommended as the symbol is a constant, unless you are linking the symbol conceptually to a different string.

Symbols are useful when you want a value that isn't equal to any other type, for example if you want to store a unique property on an object that won't be accidentally accessed with a simple string lookup.

Static Methods

Name Description
.new(name: string) Returns a new unique Symbol instance with called name
.is(other: any) Returns true if other is a Symbol instance

Example

local CHEESE = Symbol.new("CHEESE")
local FAKE_CHEESE = Symbol.new("CHEESE")
print(CHEESE == CHEESE) --> true
print(CHEESE == FAKE_CHEESE) --> false
print(tostring(CHEESE)) --> "Symbol.new(CHEESE)"

class

Classes

Create a class called name with the specified constructor. The constructor should return a plain table which will be turned into an instance of Class from a call to Class.new(...).

Instance Methods

Name Description
:toString(): string Returns a string representation of the class
:equals(other: any):boolean Returns true if the instance is equal to other
:_init() A private function which is called once the instance has been initialized

Static Methods

Name Description
.new(...): Table Returns a new instance of the class
.isInstance(value: any): boolean Returns true if value is an instance of the class

Examples

-- Create a simple Vehicle class
local Vehicle = class("Vehicle", function(wheelCount: number) return
    {
        speed = 0,
        wheelCount = wheelCount
    }
end)
function Vehicle:drive(speed)
    self.speed = speed
end
-- Create a car instance
local car = Vehicle.new(4)
car.wheelCount --> 4
car.speed --> 0
-- Drive the car
car:drive(10)
car.speed --> 10

Usage

  • When using Dash classes, private fields should be prefixed with _ to avoid accidental access.
  • A private field should only be accessed by a method of the class itself, though Dash does not restrict this in code.
  • Public fields are recommended when there is no complex access logic e.g. position.x

Symbols

Symbol definitions.


None

Symbols

A symbol representing nothing, that can be used in place of nil as a key or value of a table, where nil is illegal.

Utility functions can check for the None symbol and treat it like a nil value.

Usage

Use cases include:

  1. Creating an ordered list with undefined values in it
  2. Creating a map with a key pointing to a nil value

Debugging

These utilities assist with debugging Lua code.

assertEqual

Debugging | Maps

assertEqual(left: any, right: any, formattedErrorMessage: string?): ()

Performs a simple equality check and throws an error if left is not equal to right.

The formatted error message can be customized, which by default provides a serialization of both inputs using Dash.pretty.

The left and right values are available to be referenced in the formatted message.


cycles

Debugging | Tables

cycles(value: any, initialCycles: Cycles?): Cycles

Get information about the number of times references to the same table values appear in a data structure.

Operates on cyclic structures, and returns a Cycles object for a given value by walking it recursively.

Cycles

Name Type Description
omit { any } An array of keys which should not be visited
visited Set<Table> A set of tables which were visited recursively
refs Map<Table, number> A map from table to unique index in visit order
nextRef number The number to use for the next unique table visited

format

Debugging | Strings

format(formatString: string, ...): string

Returns the format string with placeholders {...} substituted with readable representations of the subsequent arguments. This function is a simpler & more powerful version of string.format, inspired by format! in Rust.

  • {} formats and prints the next argument using :format() if available, or a suitable default representation depending on its type.
  • {blah} formats and prints the key "blah" of the 1st argument
  • {2} formats and prints the 2nd argument.
  • {#2} prints the length of the 2nd argument. Display parameters can be combined after a : in the curly braces. Any format parameters used in string.format can be used here, along with these extras:
  • {:?} formats any value using pretty.
  • {:#?} formats any value using multiline pretty.

Examples

local props = {"teeth", "claws", "whiskers", "tail"}
format("{} is in {:#?}", "whiskers", props)
--> [[whiskers is in {"teeth", "claws", "whiskers", "tail"}]]
format("The time is {:02}:{:02}", 2, 4) -> "The time is 02:04"
format("The color blue is #{:06X}", 255) -> "The color blue is #0000FF"

Usage


formatValue

Debugging | Strings

formatValue(value: any, displayString: string): string

Format a specific value using the specified displayString.

Examples

formatValue(255, "06X") --> "0000FF"
formatValue(255.5) --> "255.5"

See

  • Dash.format - see format for a full description of valid display strings.

pretty

Debugging | Tables | Strings

pretty(object: any, options: PrettyOptions?): string

Return a pretty string serialization of object.

This implementation deals with cycles in tables and can neatly display metatables.

Optionally use an indented multiline string, limit the depth of tables, omit or pick keys.

PrettyOptions

Name Type Description
depth number? The maximum depth of ancestors of a table to display
omit { any }? An array of keys which should not be visited
multiline boolean? Whether to use multiple lines (default = false)
noQuotes boolean? Whether to drop the quotation marks around strings. By default, this is true for table keys
indent string? The indent string to use (default = "\t")
visited Set<Table>? A set of tables which have already been visited and should be referred to by reference
cycles Cycles? A cycles object returned from cycles to aid reference display

See