no :: in func decls
This commit is contained in:
@@ -223,7 +223,7 @@
|
||||
|
||||
14.5. backward type-demand propagation through call boundaries (DEFERRED)
|
||||
- a callee's result/return demand flows back through the function body to constrain
|
||||
the caller's arguments, so `R u32 :: echo(A)` (with `echo :: func(p int) int`)
|
||||
the caller's arguments, so `R u32 :: echo(A)` (with `echo func(p int) int`)
|
||||
resolves A to u32 instead of erroring at the call's result coercion
|
||||
- requires reversing the per-call data flow: a specialization's argument types
|
||||
(`spec.args`) become outputs to solve, not just inputs — a new back-edge threaded
|
||||
@@ -981,7 +981,7 @@ Milestone 23 v1 implements named error channels, native sum composition, `return
|
||||
Functions that can fail declare their error type after `!`:
|
||||
|
||||
```
|
||||
read_file :: func(path []u8) []u8 ! IoError { ... }
|
||||
read_file func(path []u8) []u8 ! IoError { ... }
|
||||
```
|
||||
|
||||
This reads as: "returns `[]u8` or fails with `IoError`." The space around `!` is idiomatic but not required.
|
||||
@@ -1035,7 +1035,7 @@ Functions that can fail with multiple error types use `|` to compose a named err
|
||||
|
||||
```
|
||||
ProcessError :: alias IoError | ParseError
|
||||
process :: func(path []u8) Ast ! ProcessError { ... }
|
||||
process func(path []u8) Ast ! ProcessError { ... }
|
||||
```
|
||||
|
||||
Parentheses are optional in the composed type and can aid readability:
|
||||
@@ -1053,7 +1053,7 @@ Inline error types are planned, but not part of milestone 23 v1. Use named enums
|
||||
Fallible functions use ordinary `return` for both channels. If the returned expression coerces to the success type `T`, the function returns success with channel code `0`. If it coerces to the error type `E`, the function returns the error with that variant's global tag id:
|
||||
|
||||
```
|
||||
parse_section :: func(p: @mut Parser) void ! ParseError {
|
||||
parse_section func(p: @mut Parser) void ! ParseError {
|
||||
start_line Line = p.line
|
||||
p.advance()
|
||||
|
||||
@@ -1086,7 +1086,7 @@ The `try` keyword unwraps a successful result or returns early with the error:
|
||||
|
||||
```
|
||||
ProcessError :: alias IoError | ParseError
|
||||
process :: func(path []u8) Ast ! ProcessError {
|
||||
process func(path []u8) Ast ! ProcessError {
|
||||
data :: try read_file(path) # read_file also returns []u8 ! ProcessError in v1
|
||||
ast :: try parse(data) # parse also returns Ast ! ProcessError in v1
|
||||
return ast
|
||||
@@ -1195,7 +1195,7 @@ Brolang provides a **thread-local global heap allocator** that is:
|
||||
```
|
||||
import "std/mem/heap"
|
||||
|
||||
process :: func(input []u8) u64 {
|
||||
process func(input []u8) u64 {
|
||||
# heap used for internal temporary work — does not escape
|
||||
temp := heap.alloc(u8, size: input.len * 2)
|
||||
defer heap.free(temp)
|
||||
@@ -1227,20 +1227,20 @@ import "std/mem"
|
||||
import "std/mem/heap"
|
||||
|
||||
# Allocation escapes via return value — requires allocator
|
||||
duplicate :: func(input []u8, allocator @mem.Allocator) []u8 {
|
||||
duplicate func(input []u8, allocator @mem.Allocator) []u8 {
|
||||
result := allocator.alloc(u8, size: input.len)
|
||||
mem.copy(result, input)
|
||||
return result # caller manages this memory
|
||||
}
|
||||
|
||||
# Allocation escapes via mutable parameter — requires allocator
|
||||
init :: func(obj: @mut MyStruct, allocator: @mem.Allocator) void {
|
||||
init func(obj: @mut MyStruct, allocator: @mem.Allocator) void {
|
||||
obj.buffer = allocator.alloc(u8, size: 100)
|
||||
# caller now knows heap memory was written into obj
|
||||
}
|
||||
|
||||
# No allocation escapes — no allocator needed
|
||||
process :: func(input: []u8) u64 {
|
||||
process func(input: []u8) u64 {
|
||||
temp := heap.alloc(u8, size: input.len)
|
||||
defer heap.free(temp)
|
||||
# ... work with temp ...
|
||||
@@ -1248,11 +1248,11 @@ process :: func(input: []u8) u64 {
|
||||
}
|
||||
|
||||
# No heap allocation at all — no allocator needed
|
||||
reset :: func(obj: @mut MyStruct) void {
|
||||
reset func(obj: @mut MyStruct) void {
|
||||
obj.count = 0
|
||||
}
|
||||
|
||||
main :: func() void {
|
||||
main func() void {
|
||||
data := duplicate("hello", heap)
|
||||
defer heap.free(data)
|
||||
|
||||
@@ -1302,7 +1302,7 @@ For specialized needs, you create explicit allocator instances. These are not gl
|
||||
import "std/mem"
|
||||
import "std/mem/heap"
|
||||
|
||||
process_file :: func(path: []u8, allocator: @mem.Allocator) !Data {
|
||||
process_file func(path: []u8, allocator: @mem.Allocator) !Data {
|
||||
# arena manages its own backing memory via heap
|
||||
arena := mem.Arena.init(heap, capacity: mem.megabytes(1))
|
||||
defer arena.deinit()
|
||||
@@ -1333,17 +1333,17 @@ EntitySystem :: struct {
|
||||
pool: mem.Pool(Entity),
|
||||
}
|
||||
|
||||
init_entities :: func(allocator: @mem.Allocator) EntitySystem {
|
||||
init_entities func(allocator: @mem.Allocator) EntitySystem {
|
||||
return EntitySystem{
|
||||
pool = mem.Pool(Entity).init(allocator, capacity: 10_000),
|
||||
}
|
||||
}
|
||||
|
||||
spawn :: func(sys: @mut EntitySystem) @Entity {
|
||||
spawn func(sys: @mut EntitySystem) @Entity {
|
||||
return sys.pool.alloc() # O(1), no fragmentation
|
||||
}
|
||||
|
||||
despawn :: func(sys: @mut EntitySystem, entity: @Entity) void {
|
||||
despawn func(sys: @mut EntitySystem, entity: @Entity) void {
|
||||
sys.pool.free(entity) # returned to pool for reuse
|
||||
}
|
||||
```
|
||||
@@ -1356,7 +1356,7 @@ As described in the escaping allocation rule, when a function heap-allocates mem
|
||||
import "std/mem"
|
||||
|
||||
# Function that uses caller's allocator
|
||||
parse :: func(input: []u8, allocator: @mem.Allocator) !ParseResult {
|
||||
parse func(input: []u8, allocator: @mem.Allocator) !ParseResult {
|
||||
buffer := allocator.alloc(u8, size: input.len)
|
||||
defer allocator.free(buffer)
|
||||
|
||||
@@ -1367,7 +1367,7 @@ parse :: func(input: []u8, allocator: @mem.Allocator) !ParseResult {
|
||||
}
|
||||
|
||||
# Caller decides which allocator to use
|
||||
main :: func() void {
|
||||
main func() void {
|
||||
# use an arena for this parsing work
|
||||
arena := mem.Arena.init(heap, capacity: mem.kilobytes(64))
|
||||
defer arena.deinit()
|
||||
|
||||
Reference in New Issue
Block a user