I like the idea of a print function that doesn’t need three casts inside it to print something, but I’m unclear on what the point is of the non-constrained version? I guess maybe it doesn’t need to box its inputs into Any?
It also seems like it would be really easy to accidentally add a parameter that doesn’t conform and fall out of the fast-path case without noticing.
The point would be if someone is trying to print a variadic argument to a function. Using the current print function, you get this error. Cannot pass value pack expansion to non-pack parameter of type 'Any'
It's possible it could be made more efficient using variadic generics, but that's not really the point.
But also, I think we only made the signature use a variadic Any parameter because we didn't have variadic generics. Now that we do, why not change it? There's no real reason print needs to type-erase its arguments.
This is unrelated, but I think there should also be a similar function added to DefaultStringInterpolation.
extension DefaultStringInterpolation {
@_disfavoredOverload
public mutating func appendInterpolation<each Segment>(_ segment: repeat each Segment) {
for segment in repeat each segment {
self.appendInterpolation(segment)
}
}
}
It’d be nice if we could have a variadic print that accepts just CustomStringConvertible, CustomDebugStringConvertible, TextOutputStreamable, and (eventually) Reflectable. These are already cast in the underlying print function. However, we might be able to use property wrappers to statically check:
func print<each Item>(
@PrintItem _ items: repeat each Item
) {}
@propertyWrapper struct PrintItem<Value> {
let value: Value
init(
wrappedValue: Value
) where Value: CustomStringConvertible { … }
// Repeat init for other protocols...
@available(*, unavailable, message: “This value is not CustomStringConvertible, or …”)
init(wrappedValue: Value) {}
}
Admittedly, we might need to help the compiler resolve the right overload when a type conforms to more than one type, but I think that’s still a good starting step.
Well that's basically a protocol OR constraint, which apparently the type system 'cannot and should not support'. I do wish it could though. One way to get around this limitation would be for the standard library to make new protocols for printing, and then make the existing string conversion protocols refinements of that protocol.
public protocol _CustomPrintable {
var _printingRepresentation: String { get }
}
protocol CustomStringConvertible: _CustomPrintable {
var description: String { get }
}
extension CustomStringConvertible {
var _printingRepresentation: String { description }
}
/* etc for other protocols */
But also, this property wrapper would still require dynamic casting to a protocol type, even if it is statically known that the value conforms to one of the printing protocols.
Yeah, I forgot to clarify that this would help with opt-in reflection metadata through Reflectable. Because if a user prints a non-Reflectable value, it would just output “value cannot be printed without reflection”. It’d be better to get a static warning or error telling the user that at compile time.
Yes, but sometimes that isn't what you want. That prints each element of the pack on a newline, compared to how the print function usually works. You would expect: