dnadoba
(David Nadoba)
1
Given a generic function that takes a Sequence as an argument, like this one:
func printTypeOfSequence<S: Sequence>(_ s: S) {
print(type(of: s))
}
and a call with an array literal with just one element, like this:
printTypeOfSequence([1])
I would expect that it prints CollectionOfOne<Int> but it prints Array<Int>.
Would the compiler be allowed to do this kind of optimisation?
1 Like
Hopefully not in this particular example, because it's an observable change in semantics as you demonstrated by printing the type. Perhaps it could be done in situations where the difference isn't observable, though.
2 Likes
xwu
(Xiaodi Wu)
3
No, the type of [1] is guaranteed to be Array in that context.
1 Like
Lantua
4
CollectionOfOne does not conform to ExpressibleByArrayLiteral anyway, so the compiler won't use CollectionOfOne<Int> for [1], at least not visibly.
3 Likes
Ben_Cohen
(Ben Cohen)
5
To be fair, Swift could (does) have optimizations that essentially do the equivalent of what is being suggested, by way of stack-allocating the array buffer and eliminating some of Array's abstractions. But as @jawbroken points out, it can only do this in (mostly) non-user-observable ways so it would never change what's happening at the level of the type system. It also needs full visibility of the code inside printTypeOfSequence to make sure e.g. the array doesn't escape.
4 Likes
It seems impossible to emulate splatting, too:
extension CollectionOfOne: ExpressibleByIntegerLiteral where Element: _ExpressibleByBuiltinIntegerLiteral {
public init(integerLiteral element: Element) {
self.init(element)
}
}
// Compiles.
printTypeOfSequence(0 as CollectionOfOne<Int>)
// Does not compile.
printTypeOfSequence(0)
printTypeOfSequence(.init(integerLiteral: 0))
But, when splatting becomes possible (i.e. ... becomes obsolete), using a literal of a single element has no possibility to break code, right?
1 Like