Open jemc opened 2 years ago
The most immediate use case to satisfy is the common map
functional operation, acting on a collection of items and emitting a new collection containing items made by transforming the input items in some arbitrary way. In Savi, this might end up being defined something like this, borrowing a bit from the forall
keyword used for this purpose in Crystal:
:class ref Array(A)
// ...
:fun map Array(B)
:for_all B
:yields for B
new_array = Array(B).new(@size)
@each -> (item | new_array << yield item)
new_array
Which should be able to be invoked like this, with the compiler using the yield block's result type to infer the type for B
as USize
, making the overall call return an Array(USize)
:
names = ["Alice", "Bob", "Cyril"]
sizes = names.map -> (name | name.size)
Note that this approach doesn't introduce a special syntax for explicitly specifying type parameters on the caller's side.
I think we can avoid introducing new syntax for this if we take an approach similar to Swift, wherein the type parameters must be trivially inferrable from being used somewhere else in the signature.
The example above had the B
type trivially inferrable from the yield block result type (as noted by the explicit :yields for B
declaration).
In Swift, if there is no clear way to infer via some other part of the function signature, the common workaround is to add a new function parameter that accepts the type to use as a value. This will probably adapt well to Savi, where we can use the non
cap to pass a type as a value without needing to be holding an instantiation of it.
As an example of how that might look, here's a function that just returns a new array of an arbitrary type:
:fun make_array(a A'non) Array(A)
:for_all A
Array(A).new
The tricky thing about this case in today's Savi language, is that we won't necessarily know what cap to use for the A
(because we have nothing to infer the cap from, as the type parameter is only inferrable through the a A'non
) parameter, which obscures the "true" cap of A
with the non
override.
However, I suspect this difficulty will be alleviated in the new capabilities system, so I don't want to worry too much about this case yet.
Accordingly, I'm marking this as blocked by the new capabilities system, though perhaps if pressed we could split the ticket in half to create one blocked ticket and one unblocked ticket, leaving the blocked case for a later effort.
Currently Savi has no generic functions (functions with type parameters). We only have generic types (like
Array
andMap
).We want to add them, in at least some basic useful form, even if we don't satisfy every possible use case at the start.