The use case is the dynamicMember API for bridging to a language where return results are absent most of the time, but are still expressed in Swift with .undefined enum case. This API returns a closure, which it would be great to mark as @discardableResult if it were possible.
Has this been considered before? If so, what are the downsides?
I think the biggest additional complexity would come from the additional conversions needed to make this a type attribute. Is there an implicit conversion from () -> Int to @discardableResult () -> Int? How about the other way around? Should the compiler warn on one or the other? How do you silence such a warning?
This can all be sidestepped by putting the @discardableResult on the let (or on a parameter) rather than on the type. That would be an almost trivial addition, but wouldn't handle your original motivating use case where you want it for a return value.
I don't think there's a need to warn about the implicit conversion. @discardableResult by itself is explicit enough to signal user's intent. Additional warnings about conversions with this attribute would only make things more confusing, in my opinion.
If there is another overload of the subscript that returns a (ConvertibleToJSValue...) -> Void, does Swift pick up the right one when the return value is ignored?
IMO it's not so much whether Jordan's questions are answerable for a specific use case as much as whether these answers make sense for everyone (or at least a large majority) of people who could want to add @discardableResult to a function type. I personally wouldn't know how to evaluate whether these are the right decisions without more projects stepping forward with related use cases.
In what sense, then, is @discardableResult a type-level attribute under this scheme? Isn’t this indistinguishable in behavior from @discardableResult being an attribute of the binding?
An attribute on the binding is what makes sense with the limited example I gave in the original post. I'm looking for a broader behavior, where we have a function returning closures. I'd like results returned by such closures to be discardable:
enum JSValue {
case string(String)
// ...
case undefined
}
// body of `closureFactory` made trivial for demonstration purposes
func closureFactory() -> (() -> JSValue) {
{ .undefined }
}
// next line triggers a warning about discarded result
closureFactory()()
// have to write it this way to avoid the warning
_ = closureFactory()()
With this example it is clear that what you want is a new type attribute as Jordan said. A declaration attribute won't help here, because it won't be seen outside of the function:
func closureFactory() -> (() -> JSValue) {
@discardableResult func closure() -> JSValue { .undefined }
return closure
}
// the next line still triggers a warning about discarded result
closureFactory()()
Perhaps Max means that in the following simplified example:
func foo() -> Int { 0 }
@discardableResult func bar() -> Int { 0 }
let x = foo
x() // Warning: Result of call to function returning 'Int' is unused
let y = bar
y() // Warning: Result of call to function returning 'Int' is unused
if discardableResult is moved to the type attribute the warning for y() would disappear (which makes total sense to me). @Max_Desiatov, correct me if I got you wrong.