This idea was discussed long ago and the present design was selected.
But this design was discussed in the proposal as a "future direction",
because @discardableResult was chosen partially because it was easier to
implement. It says so [in the proposal][1]. This is why we write formal
proposals, Xiaodi—so we remember why we made the decisions we made.
You're right that it was chosen in part because it was easier to implement.
But this does not at all mean that "@discardable" is the blessed future
direction; whether it is wise ever to adopt the "@discardable" design was
not thoroughly evaluated--it was simply decided that, for Swift 3,
@discardableResult was preferable to @discardable in the totality of things.
In my view, this means the "@discardable" idea needs to meet a higher bar
than a never-before presented idea, not a lower one.
* * *
Now, the proposal specifically suggests we delay `@discardable` "until
such time as there's a strong motivation to use such an approach". Do we
have such a motivation?
I actually think we do (although it may not be strong enough). Currently,
we have two types—`Void` (as well as optionals, of any depth, wrapping
`Void`) and `Never`—which are "implicitly discardable". That is, you don't
need to mark a function which returns those types with
`@discardableResult`; it inherently is. This is currently handled with [an
ad-hoc test][2], but I think we should consider strengthening and opening
up this mechanism.
Why? Because there are other types we would like to be implicitly
discardable. You can already make an argument for types like `Array<Void>`,
but concurrency will bring types like `Future<Void>` which could get pretty
strong benefits from it. Since we're planning to leave a lot of async stuff
to userspace, there ought to be a userspace way to mark types as implicitly
discardable. And if discardability stems from the type system, it's pretty
natural to make ad-hoc discardibility a property attached to the type, too.
(We could then mark `Never` with @discardable, make tuples discardable
unless one of their elements is not discardable, make optionals discardable
if the type they wrap is discardable, and—et voilà!—we have a nice, general
language feature with as little magic as we can manage.)
[1]: GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
proposals/0047-nonvoid-warn.md#future-directions
[2]: GitHub - apple/swift at e907031d3d4555e917ca3ad7fffeac7f580331a0
7f580331a0/lib/Sema/TypeCheckStmt.cpp#L991
I am not sure this is entirely wise, for a few reasons.
a) I sure don't know why you'd want to return `Void?`, but if you do, it
doesn't follow that it should be discardable simply because `Void` is
discardable. It may well be so, or it may be (for some odd reason) that
it's the return type of a pure function that certainly shouldn't be
discardable.
b) Based on (a), I don't think that types composed of discardable types are
therefore discardable. I need to think this through further.
c) If you reject (b), then this brings up a larger issue.
`@discardableResult` is an attribute of the function; here, you're saying
that not only should the _spelling_ be moved to the other side of the
function arrow, but that the attribute should apply to the type. Would we
then have to invent a new overriding attribute for functions that return
`@discardable` types which don't want their return value to be discardable?
Like, a `@nondiscardableResult func foo() -> Void? /* implicitly
discardable type */`? I think this further demonstrates how it's not really
the type but the function that we want to annotate.
d) Does a class that override a `@discardable` type inherit that
annotation? If not, they it's kind of a weird exception to the inheritance
thing, no? If so, then we'd need a @nondiscardable annotation to do
type-level overrides of @discardable.
e) `Never` was explicitly designed to have no magic that any other
uninhabited enum would not get. To stick with this design, every enum
without any cases would have to be implicitly `@discardable`. This might be
surprising.
f) Speaking of enums: if types are discardable, then some errors are
discardable. By contrast, we do not currently have a `@discardableError`
annotation. What does it mean if a function throws a "discardable error"?
Can we choose not to catch it?
···
On Wed, Oct 18, 2017 at 9:29 PM, Brent Royal-Gordon <brent@architechies.com> wrote:
On Oct 9, 2017, at 11:02 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote: