Typed func signatures are verbose at every use site, and the verbosity compounds because the same signature is repeated across parameters, struct fields, and locals:
do each(arr [int], f func(int)) { }
do fold(arr [int], init int, f func(int, int) -> int) -> int { }
const Wrapper struct {
on_start func(int) -> int
on_error func(string, int) -> bool
}
Naming the signature once removes the clutter without erasing the signature from the type, so argument counts, argument types, and return types stay checked:
alias Visitor = func(int)
alias Folder = func(int, int) -> int
alias Handler = func(int) -> int
alias ErrHook = func(string, int) -> bool
do each(arr [int], f Visitor) { }
do fold(arr [int], init int, f Folder) -> int { }
const Wrapper struct {
on_start Handler
on_error ErrHook
}
This is how the languages Grayscale draws from solve it — Go's type Handler func(int) int, Odin's Proc :: proc(int) -> int, Rust's type Op = fn(i32) -> i32. None of them offers a signature-erasing function type, because it costs call-site checking and return-type inference.
Current state
Most of this already works and is undocumented. parse_alias_declaration calls parse_complex_type, which encodes func(...) as the flat "func(int)->int" type-name string the type system already uses, so aliases picked up func signatures for free. Verified working on HEAD:
- func alias as a parameter type, called through the parameter
- func alias as a standalone
const variable type
- void signatures (
alias Sink = func(int)) and multi-parameter signatures (alias Pair = func(int, string) -> bool)
type_of() returns the underlying signature (func(int)), consistent with aliases being erased at compile time
- signature mismatch through an alias reports
E3066 and prints the underlying signature in the message
What does not work is the struct-field position, which is one of the two places the clutter is worst. That defect is filed separately as a bug; this issue is not complete until it lands.
Scope
1. STANDARD.md §3.5
The "Can alias" list reads as exhaustive — "primitives, structs, enums, arrays ([T]), maps (map[K:V]), and pointers (^T)" — and omits func signatures, which is why the capability is invisible. Add them with an example. State explicitly whether the aliasable and non-aliasable lists are exhaustive; a reader currently cannot tell whether an omission means unsupported or unmentioned.
2. STANDARD.md §7.6
Cross-reference aliasing from the section that introduces func signatures, since that is where a reader feeling the clutter is standing. §7.6.2 (parameters) and §7.6.4 (struct fields) are the two positions worth naming. §7.6.4 requires a typed signature for struct fields — state that an alias of a typed signature satisfies that requirement.
3. Interaction with the bare-func rules
§7.6.3 disallows typed func signatures as array element types ([func(int)->int]), directing users to [func] or [func, N]. An alias of a func signature is a typed signature, so [Handler] must be rejected by the same rule and with the same diagnostic. It currently fails with a confusing E3001 type mismatch instead — this is the general composite-position alias defect, tracked separately, and this issue only needs the resulting behavior documented once that lands.
4. Language rule to record
An alias of a func signature is interchangeable with the signature everywhere the signature is legal, and illegal everywhere the signature is illegal. No new positions become legal because a name was put in front of the type.
Tests
Pass coverage:
- func alias as a parameter type, called through the parameter
- func alias as a struct field type, both struct-literal and
new() pointer forms
- void signature alias and multi-parameter signature alias
- alias chaining (
alias A = func(int) -> int then alias B = A)
type_of() through a func alias
- a func alias and its literal signature used interchangeably in the same program
Fail coverage:
- mismatched reference assigned through a func alias reports
E3066
[Handler] as an array element type is rejected by the §7.6.3 rule
- bare
func as a struct field type still reports E3130
Typed func signatures are verbose at every use site, and the verbosity compounds because the same signature is repeated across parameters, struct fields, and locals:
Naming the signature once removes the clutter without erasing the signature from the type, so argument counts, argument types, and return types stay checked:
This is how the languages Grayscale draws from solve it — Go's
type Handler func(int) int, Odin'sProc :: proc(int) -> int, Rust'stype Op = fn(i32) -> i32. None of them offers a signature-erasing function type, because it costs call-site checking and return-type inference.Current state
Most of this already works and is undocumented.
parse_alias_declarationcallsparse_complex_type, which encodesfunc(...)as the flat"func(int)->int"type-name string the type system already uses, so aliases picked up func signatures for free. Verified working on HEAD:constvariable typealias Sink = func(int)) and multi-parameter signatures (alias Pair = func(int, string) -> bool)type_of()returns the underlying signature (func(int)), consistent with aliases being erased at compile timeE3066and prints the underlying signature in the messageWhat does not work is the struct-field position, which is one of the two places the clutter is worst. That defect is filed separately as a bug; this issue is not complete until it lands.
Scope
1. STANDARD.md §3.5
The "Can alias" list reads as exhaustive — "primitives, structs, enums, arrays (
[T]), maps (map[K:V]), and pointers (^T)" — and omits func signatures, which is why the capability is invisible. Add them with an example. State explicitly whether the aliasable and non-aliasable lists are exhaustive; a reader currently cannot tell whether an omission means unsupported or unmentioned.2. STANDARD.md §7.6
Cross-reference aliasing from the section that introduces func signatures, since that is where a reader feeling the clutter is standing. §7.6.2 (parameters) and §7.6.4 (struct fields) are the two positions worth naming. §7.6.4 requires a typed signature for struct fields — state that an alias of a typed signature satisfies that requirement.
3. Interaction with the bare-
funcrules§7.6.3 disallows typed func signatures as array element types (
[func(int)->int]), directing users to[func]or[func, N]. An alias of a func signature is a typed signature, so[Handler]must be rejected by the same rule and with the same diagnostic. It currently fails with a confusingE3001type mismatch instead — this is the general composite-position alias defect, tracked separately, and this issue only needs the resulting behavior documented once that lands.4. Language rule to record
An alias of a func signature is interchangeable with the signature everywhere the signature is legal, and illegal everywhere the signature is illegal. No new positions become legal because a name was put in front of the type.
Tests
Pass coverage:
new()pointer formsalias A = func(int) -> intthenalias B = A)type_of()through a func aliasFail coverage:
E3066[Handler]as an array element type is rejected by the §7.6.3 rulefuncas a struct field type still reportsE3130