ddonche/goblin-lang
0.46.24
1
0
reference concepts
[[collection-utilities]]

Collection Utilities


Goblin uses its own unique syntax for dealing with collections than you might be accustomed to coming from other languages. This document explains them all, along with the reasoning for this design choice.

This document reflects the current rules:

  • Bare names operate on the entire collection.
  • Each operation has a _random variant replacing the old random-default behavior.
  • Bang (!) means mutation, as always.

Unified Data Structure Operations

Goblin eliminates the chaos of dozens of different collection APIs by reducing everything to five core operations, each of which supports:

  • entire-collection mode (bare name)
  • random element mode (_random)
  • targeted modes (_first, _last, _at, _where, _all)
  • mutating forms (add !)
Tip
Goblin's model is simple: Everything is CRUD.1

Collection Size

All collections support:

  • :len(collection) — number of elements
  • :count(collection) — alias of len

items | [10, 20, 30]
:say(:len(items))    /// 3
:say(:count(items))  /// 3
items | [10, 20, 30]
:say(:len(items))    /// 3
:say(:count(items))  /// 3


Mutation Rules

Goblin uses bang semantics:

  • operation returns a modified copy — the original is unchanged
  • operation! mutates in place

items | [1, 2, 3]

/// non-mutating — items unchanged, result returned
new_items | :put_last(items, 4)
:say(items)      /// [1, 2, 3]
:say(new_items)  /// [1, 2, 3, 4]

/// mutating — items changed in place
:put_last!(items, 4)
:say(items)      /// [1, 2, 3, 4]
items | [1, 2, 3]

/// non-mutating — items unchanged, result returned
new_items | :put_last(items, 4)
:say(items)      /// [1, 2, 3]
:say(new_items)  /// [1, 2, 3, 4]

/// mutating — items changed in place
:put_last!(items, 4)
:say(items)      /// [1, 2, 3, 4]


GET (Read)

Returns elements without modifying the collection.

items | [10, 20, 30, 40, 50]

/// entire collection
:get(items)           /// [10, 20, 30, 40, 50]

/// random element
:get_random(items)    /// 30 (or any other)

/// first / last
:get_first(items)     /// 10
:get_last(items)      /// 50

/// at index
:get_at(items, 2)     /// 30

/// where — pass the name of an action as a string
act is_big(x) => return x > 25
:get_where(items, "is_big")   /// [30, 40, 50]

/// all — returns the entire collection (same as bare get)
:get_all(items)       /// [10, 20, 30, 40, 50]
items | [10, 20, 30, 40, 50]

/// entire collection
:get(items)           /// [10, 20, 30, 40, 50]

/// random element
:get_random(items)    /// 30 (or any other)

/// first / last
:get_first(items)     /// 10
:get_last(items)      /// 50

/// at index
:get_at(items, 2)     /// 30

/// where — pass the name of an action as a string
act is_big(x) => return x > 25
:get_where(items, "is_big")   /// [30, 40, 50]

/// all — returns the entire collection (same as bare get)
:get_all(items)       /// [10, 20, 30, 40, 50]

Maps work the same with string keys:

config | {"host": "localhost", "port": "4242"}
:get_at(config, "port")   /// "4242"
config | {"host": "localhost", "port": "4242"}
:get_at(config, "port")   /// "4242"

Note
You do not use the bang form with get. Nothing will happen.

PUT (Insert)

Inserts a new element into the collection.

items | [10, 20, 30]

/// first / last
:put_first!(items, 0)
/// items → [0, 10, 20, 30]

:put_last!(items, 99)
/// items → [0, 10, 20, 30, 99]

/// at index
:put_at!(items, 2, 15)
/// items → [0, 10, 15, 20, 30, 99]

/// random position
:put_random!(items, 55)
/// inserts 55 at a random position
items | [10, 20, 30]

/// first / last
:put_first!(items, 0)
/// items → [0, 10, 20, 30]

:put_last!(items, 99)
/// items → [0, 10, 20, 30, 99]

/// at index
:put_at!(items, 2, 15)
/// items → [0, 10, 15, 20, 30, 99]

/// random position
:put_random!(items, 55)
/// inserts 55 at a random position


UPDATE (Modify)

Replaces elements in the collection.

items | [1, 2, 3, 4, 5]

/// entire collection — replaces all contents
:update!(items, [9, 9, 9])
/// items → [9, 9, 9]

/// first / last
items | [1, 2, 3, 4, 5]
:update_first!(items, 99)
/// items → [99, 2, 3, 4, 5]

:update_last!(items, 0)
/// items → [99, 2, 3, 4, 0]

/// at index
:update_at!(items, 2, 33)
/// items → [99, 2, 33, 4, 0]

/// random element
:update_random!(items, 77)
/// replaces a random element with 77

/// where — replaces all matching elements with a value
act is_big(x) => return x > 3 
items | [1, 2, 3, 4, 5]
:update_where!(items, "is_big", 99)
/// items → [1, 2, 3, 99, 99]

/// all — replaces entire collection (same as bare update!)
:update_all!(items, [0, 0, 0])
/// items → [0, 0, 0]
items | [1, 2, 3, 4, 5]

/// entire collection — replaces all contents
:update!(items, [9, 9, 9])
/// items → [9, 9, 9]

/// first / last
items | [1, 2, 3, 4, 5]
:update_first!(items, 99)
/// items → [99, 2, 3, 4, 5]

:update_last!(items, 0)
/// items → [99, 2, 3, 4, 0]

/// at index
:update_at!(items, 2, 33)
/// items → [99, 2, 33, 4, 0]

/// random element
:update_random!(items, 77)
/// replaces a random element with 77

/// where — replaces all matching elements with a value
act is_big(x) => return x > 3 
items | [1, 2, 3, 4, 5]
:update_where!(items, "is_big", 99)
/// items → [1, 2, 3, 99, 99]

/// all — replaces entire collection (same as bare update!)
:update_all!(items, [0, 0, 0])
/// items → [0, 0, 0]


DELETE (Remove)

Removes elements from the collection.

items | [1, 2, 3, 4, 5]

/// entire collection — clears it
:delete!(items)
/// items → []

items | [1, 2, 3, 4, 5]

/// first / last
:delete_first!(items)
/// items → [2, 3, 4, 5]

:delete_last!(items)
/// items → [2, 3, 4]

/// at index
:delete_at!(items, 1)
/// items → [2, 4]

/// random element
:delete_random!(items)
/// removes one random element

/// where — removes all matching elements
act is_big(x) => return x > 3 
items | [1, 2, 3, 4, 5]
:delete_where!(items, "is_big")
/// items → [1, 2, 3]

/// all — same as bare delete!
:delete_all!(items)
/// items → []
items | [1, 2, 3, 4, 5]

/// entire collection — clears it
:delete!(items)
/// items → []

items | [1, 2, 3, 4, 5]

/// first / last
:delete_first!(items)
/// items → [2, 3, 4, 5]

:delete_last!(items)
/// items → [2, 3, 4]

/// at index
:delete_at!(items, 1)
/// items → [2, 4]

/// random element
:delete_random!(items)
/// removes one random element

/// where — removes all matching elements
act is_big(x) => return x > 3 
items | [1, 2, 3, 4, 5]
:delete_where!(items, "is_big")
/// items → [1, 2, 3]

/// all — same as bare delete!
:delete_all!(items)
/// items → []


REAP (Read + Remove)

Returns an element and removes it from the collection in one step. Requires bang (!) to mutate.

items | [10, 20, 30, 40, 50]

/// first
head | :reap_first!(items)
/// head → 10, items → [20, 30, 40, 50]

/// last
tail | :reap_last!(items)
/// tail → 50, items → [20, 30, 40]

/// at index
val | :reap_at!(items, 1)
/// val → 30, items → [20, 40]

/// random
pick | :reap_random!(items)
/// pick → 20 or 40, removed from items

/// where — returns and removes all matching elements
items | [1, 2, 3, 4, 5]
act is_big(x) => return x > 3 
big | :reap_where!(items, "is_big")
/// big → [4, 5], items → [1, 2, 3]
items | [10, 20, 30, 40, 50]

/// first
head | :reap_first!(items)
/// head → 10, items → [20, 30, 40, 50]

/// last
tail | :reap_last!(items)
/// tail → 50, items → [20, 30, 40]

/// at index
val | :reap_at!(items, 1)
/// val → 30, items → [20, 40]

/// random
pick | :reap_random!(items)
/// pick → 20 or 40, removed from items

/// where — returns and removes all matching elements
items | [1, 2, 3, 4, 5]
act is_big(x) => return x > 3 
big | :reap_where!(items, "is_big")
/// big → [4, 5], items → [1, 2, 3]


Traditional vs. Goblin

Other languages have unique words depending on what type of collection you are working with, and where you are performing the operation. We believe this adds unnecessary mental overhead. In Goblin, you only need to know what you are doing and where.

Traditional Goblin
push :put_last!
pop :reap_last!
shift :reap_first!
unshift :put_first!
filter :get_where
splice :update_where! / :delete_where!
random ops (usually manual) _random everywhere
replace whole collection :update!

Supported Collections

  • Arrays
  • Maps
  • Sets
  • Queues
  • Stacks
  • Deques

Trees coming soon.


Summary

Goblin's collection system has:

  • Bare = whole collection
  • _random = random element
  • _first / _last = positional ends
  • _at = specific index or key
  • _where = filtered by predicate (action name as string)
  • _all = every element
  • Bang = mutation
  • CRUD as the universal model
  • Identical API across all collection types

  1. CodeAcademy. (n.d.). What is CRUD? Explained. CodeAcademy. https://www.codecademy.com/article/what-is-crud-explained