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
_randomvariant 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
!)
Collection Size
All collections support:
:len(collection)— number of elements:count(collection)— alias oflen
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:
operationreturns a modified copy — the original is unchangedoperation!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"
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
-
CodeAcademy. (n.d.). What is CRUD? Explained. CodeAcademy. https://www.codecademy.com/article/what-is-crud-explained ↩