I'm not a big fan of *
as it doesn't transmit the meaning to me, but thanks for updating the proposal clarifying why ...
is discarded. For people like me with some experience in other languages that use ...
it would make it hard to not ask ?why not? on the proposal review
FWIW, to the extent that the revised proposal's dismissal of as ...
relates to what I suggested above, the reasoning doesn't actually apply.
I did not propose as ...
as shorthand for as T...
. I proposed the syntax as ...
as syntax to indicate splatting. There is no need for consistency with as <sometype>
, and there is no problem with heterogenous collections.
Taking a wider view, I'm also unhappy that the proposal treats "splat" as an operator, when it clearly isn't. Specifically, *<array>
(or however it's spelled) as an expression has the same type and value as <array>
.
What we're trying to do, surely, is to come up with syntax to treat an array as a list in parameter position. Trying to formalize this as an expression (via an operator) seems misguided to me, especially because that promotes artificial constraints on the design of the feature — and ends up complexifying both syntax and usability.
Of course, it's perfectly fine for the implementation of this feature to treat it as a pseudo-operator limited to specific contexts, if that's the most natural path to a solution. But let's not deform the feature because of that.
if ...
is not intended to represent a type in that case, I don't think it makes sense to use it with the type coercion operator.
I think it's important to note, the restrictions imposed on this new operator are the same ones imposed on &
today when working with inout arguments.
What about
foo(array as Variadic)
? Since we can do as Optional
and the likes. This would also add future direction where Variadic
is a simple Collection
subprotocol should we want to support other types.
There are currently 3 operators that involve the word as
(as
, as?
and as!
):
https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
(under the heading "Type-Casting Operators")
I'm suggesting a fourth (as...
, although I'd prefer that internal whitespace be allowed, so as ...
too).
If it's an operator, it's not a "type-casting" operator, but rather a "type-reinterpretation" operator, or something like that. I don't see why the semantics are a bar to spelling it using as
— if the community likes the spelling.
I thought the previous as T...
syntax was good, because it was similar to toll-free bridging (cf. as CFArray
and as NSArray
).
Here's an alternative to the prefix *
operator, using three commas after the variadic parameter/argument.
Variadic parameter:
public func print(_ items: Any,,,)
public func print(_ items: Any,,,
separator: String = " ",
terminator: String = "\n")
Variadic argument (splatting):
let items: [Any]
print(items,,,)
print(items,,, separator: "\t")
Notes:
-
There are three trailing commas when the last parameter/argument is variadic.
-
There are only three (not four) commas when a variadic parameter/argument is followed by another parameter/argument.
I still don't see a case for an operator being required to do something that's basically a compiler/syntax constraint.
I understand having caution around implicit conversion, but that's not what's happening with [T]
-> T...
. T...
is not a Type. At least not (currently) in Swift. It's syntactic sugar that allows a variadic number of parameters. The Type of T...
is functionally (and literally other than at the call site) [T]
The only ambiguity in T...
is when T
and Array
share an underlying Type. The main pain point here is print()
and can be handled the same way as passing an Optional
to Any...
: default to the most base-Type unless specifically cast by the User, with an accompanying warning about the ambiguity. I believe this would match the current behavior and shouldn't cause any source compatibility issues.
This is coming from a usage perspective and I'm guessing it complicates things in regards to implementation, but IMO passing an array as a variadic is clearly ergonomically the best at the call point.
Edit: made a few more revisions, and added an example involving overrides of methods which take varargs
I support this proposal, and the use of the *
operator syntax, eg, *args
.
@owenv What's the status on this proposal? I've seen a couple other tentative proposals floating around on the forums, but nothing definitive. Has anyone from the core team commented on this proposal or any of the others like it? We NEED a splat operator in swift. I would prefer using the *
symbol, but I would be satisfied with anything as long as it gets implemented.
This is on hold until the design of variadic generics is farther along. The consensus is we shouldn't make smaller incremental improvements like this one until we're confident they won't limit the design space for more general features.
What's slated to change about variadic generics? Are you simply referring to the fact that functions/methods can use variadic parameters with generic types, as in
func test<T>(items: T...) { ... }
or something else?
As I understand, variadic generics are something like this:
func item<T1, T2, ..., Tn>(item1: T1, item2: T2, ..., itemN: Tn)
@kireev165
Could you provide a more detailed example? I'm not sure how the above function would work.
Any progress?
Looking forward to this! :)
In my opinion, any syntax for converting an array to a variadic adds completely unnecessary complexity to the language and pollutes the syntax. It seems to me that the only adequate and intuitive way is to allow the array to be passed where the variadic is expected. I think even if an operator is added to Swift, I will continue to duplicate the methods.
Being able to pass a collection/sequence where variadic is expected, feels like the most simplistic organic approach. That would help greatly simplify the call site where variadic is expected. It confuses me that this wouldn't be the approach since using a parameter that uses variadic is represented as a sequence, or at least it appears to be, since it's applied to another collection with the -append(contentsOf:)
method, as well as accessing an element requires using for each.