Memory by Example
Blorp gives ordinary data value semantics, while ARC and COW keep copies efficient. Channels and scoped resources have different ownership rules.
Value Semantics
Assignment creates another name for the same value, not a mutable reference to be changed through either name.
original: List[Int] = [1, 2]
snapshot: List[Int] = original
ARC/COW
ARC and copy-on-write let containers share storage until an update would be observable.
updated: List[Int] = snapshot.append(3)
print(original.to_string()) -- prints: [1, 2]
print(snapshot.to_string()) -- prints: [1, 2]
print(updated.to_string()) -- prints: [1, 2, 3]
Aliases
append through one name returns a new list value; the earlier alias keeps seeing the original list.
func main(args: List[String]) -> Void:
a: List[Int] = [1]
b: List[Int] = a
c: List[Int] = b.append(2)
Channel Handles
Copying a channel copies a handle to the same endpoint, not its queued data. Sending or sealing through either handle affects that endpoint. This is explicit communication, unlike updating an ordinary copied list.
import:
channel: RecvAttempt(RecvValue, RecvSealed), try_recv_attempt, wait_send
func copied_channel_shares_endpoint() -> Bool:
original: Channel[Int] = channel(1)
copy = original
sent = wait_send(copy, 42).is_ok()
seal(copy)
-- Sealing either handle seals the same endpoint; buffered data still drains.
received = match try_recv_attempt(original):
RecvValue(42): True
_: False
sealed = match try_recv_attempt(original):
RecvSealed: True
_: False
sent and received and sealed
func main(args: List[String]) -> Int:
shared = copied_channel_shares_endpoint()
print(shared.to_string()) -- stdout: True
if shared:
0
else:
1
Closure Capture
A closure cannot capture a var binding. Bind an immutable snapshot first; later rebinding the original does not change the captured value. Scoped resource handles cannot be captured at all.
pure func make_adder(base: Int) -> pure (Int) -> Int:
pure func(x): x + base
func snapshot_value() -> Int:
var count: Int = 7
snapshot: Int = count
read_snapshot = pure func() -> Int: snapshot
count = 9
read_snapshot()
func main(args: List[String]) -> Void:
print(snapshot_value().to_string()) -- stdout: 7 (not 9)
Example
pure func make_label(prefix: String) -> pure (Int) -> String:
pure func(n: Int): prefix + n.to_string()
func main(args: List[String]) -> Void:
original: List[Int] = [1, 2, 3]
snapshot: List[Int] = original
updated: List[Int] = snapshot.append(4)
label = make_label("count: ")
print(original.length()) -- prints: 3
print(updated.length()) -- prints: 4
print(label(updated.length())) -- prints: count: 4
Try it
blorp run value-semantics.brp