If you want to write a function that works on a span(integer), it's trivial: you just accept the value and use it. If you want to write a function that works on a span of any type, you have higher-effort options with some downsides:
edit the function into the make_spanT that creates all of the specialized functions. (downside: your function can't go where you wanted to put it. You have to 'upstream' it.)
accept an auto instead (downside: callsite type inference is less helpful, you can start passing arrays when you wanted to construct a span() and pass that)
write a concept that handles type inference and has appropriate errors (downside: this is more work, it's less clear what you're intending)
write your own generic type and have callers specialize it to pull out the function (downside: lots of ceremony for the caller to do vs. calling a function, and the caller very easily hits "cannot do type cast on generics" errors)
require 'span'
## local function make_spanlength(T)
local r = @record{}
function r.call(sp: span(#[T]#))
return #sp
end
## return r
## end
local spanlength: type = #[generalize(make_spanlength)]#
print((@spanlength(@byte)).call('hello'))
Feature description
Skip the need for the dummy record and its metafield:
require 'span'
## local function make_spanlength(T)
local function spanlengthT(sp: span(#[T]#))
return #sp
end
## return spanlengthT
## end
local spanlength: type = #[generalize(make_spanlength)]#
print(spanlength(byte)('hello'))
Currently that's a "cannot do type cast on generics" error, but it seems like reasonable syntax. Trying to avoid that error exposes others:
print(@spanlength(byte)('hello')) -- unclosed parenthesis
print((@spanlength(byte))('hello')) -- error in generic instantiation: expected a symbol holding a type in generic return, but got something else
This feels more like D or C++ style generics with a second set of arguments, but it retains the flexibility of the current system to specialize arbitrarily over multiple types or values.
Alternatives
Accepting auto in generic parameters. This is natural for the simple case, but you still have to add explicit checks if you want, for example, two spans of the same inner type.
require 'span'
local function spanlength(sp: span(auto))
return #sp
end
print(spanlength('hello'))
Zig-like generics: permitting comptime type arguments to appear elsewhere in the function parameters. This is also flexible but more verbose when the type inferencer might not need the help.
require 'span'
local function spanlength(T: type <comptime>, sp: span(T))
return #sp
end
print(spanlength(byte, 'hello'))
Feature motivation
If you want to write a function that works on a
span(integer)
, it's trivial: you just accept the value and use it. If you want to write a function that works on a span of any type, you have higher-effort options with some downsides:edit the function into the
make_spanT
that creates all of the specialized functions. (downside: your function can't go where you wanted to put it. You have to 'upstream' it.)accept an
auto
instead (downside: callsite type inference is less helpful, you can start passing arrays when you wanted to construct aspan()
and pass that)write a concept that handles type inference and has appropriate errors (downside: this is more work, it's less clear what you're intending)
write your own generic type and have callers specialize it to pull out the function (downside: lots of ceremony for the caller to do vs. calling a function, and the caller very easily hits "cannot do type cast on generics" errors)
Feature description
Skip the need for the dummy record and its metafield:
Currently that's a "cannot do type cast on generics" error, but it seems like reasonable syntax. Trying to avoid that error exposes others:
This feels more like D or C++ style generics with a second set of arguments, but it retains the flexibility of the current system to specialize arbitrarily over multiple types or values.
Alternatives
auto
in generic parameters. This is natural for the simple case, but you still have to add explicit checks if you want, for example, two spans of the same inner type.