I was writing a new version of a fixed-size array manifesto, and I got to the flatten-into-buffer functions:
func withFlattening<T: [... ; some Any], R>(of: T, body: (UnsafeBufferPointer<T.Element>) throws -> R) rethrows -> R
Then I finally realized that all the earlier parts of the report use FSA existentials another way:
let intArray: [3 ; Int] = [1, 2, 3]
let doubleArray: [2, 2 ; Double] = [1.0, 2.0, 3.0, 4.0]
var numericArray: [... ; some Numeric] = intArray
//...
numericArray = doubleArray
I was using a FSA existential as a variable's type instead of just a generic constraint. This second use is that "generalized existential" feature I've read about here, right? We currently don't have it. (We can't make a Numeric
variable, let alone have it store Int
and Double
values at different times.)
Which brings up my problem. If we don't have generalized existentials now, then I probably shouldn't introduce a version of them in this manifesto. What if we add them later, but they have incompatibilities with the FSA ones? It would be better if I left them out, then when/if generalized existentials are added overall, everything would be consistent.
But some of the ideas already assume I can use FSA existentials as returnable types:
func extents<T: [... ; some Any]>(of a: T) -> [_ ; Int]
What would this return in a world where generalized existential values couldn't be returned?
func extents<T: [... ; some Any]>(of a: T) -> [#extentCountOf(T) ; Int]
could work, assuming we can't create constructs where the number of dimensions in T
would only be known at run-time. Also, I think without FSA generalized existentials, we would have to design a AnyFSA<Element>
type that works like AnySequence
, AnyHashable
, etc.
Or I could just go ahead and design generalized existentials for FSAs, and maybe we can later design any-type generalized existentials off my work. (There would still be consistency in this route.)