Changing the spelling of @discardableResult or discard

The discard operator and @discardableResult both use the term "discard" in similar, but critically distinct ways. @discardableResult uses the term to indicate that a value can be implicitly destroyed, while the discard operator uses the term to indicate that a noncopyable value should be destroyed without running the deinitializer.

This inconsistency may be misleading to users who aren't familiar with noncopyable types, and I personally find it annoying. Plus, I think there's still time to change it — while noncopyable types are already part of the language, they haven't gotten significant usage yet due to the fact that they don't support protocols and borrowing switches. And many of the noncopyable types that do exist don't use discard.

I think we should consider deprecating the discard operator and adding something else. In Rust, this operation is called forget, so we could use that name. Or, we could turn discard into a function named something like discardWithoutRunningDeinitializer (obviously, the exact name can be bikeshedded). The advantage of turning it into a function is that the name can be much more descriptive of what the function does. The discard operator doesn't seem to be used as much as most other operators, so a function might be more appropriate.

We could also consider changing the name of @discardableResult, but that would likely cause significantly more churn.

What do you all think?

5 Likes

IMHO this would be good alternative for @discardableResult syntax if to change it:

func foo() -> discardable Int { ... }

That would still be quite close to "discard" though.

1 Like

Synonyms include dispensable, expendable and droppable.

I do prefer this syntax for @discardableResult (just because it's pretty commonplace), and to be honest, I've literally never used the discard operator.

I’ve been meaning to make a post soon about this type of idea. It seems to me that the discardability of a value is information that should be carried by the value, not by the function that produces it. If I pass a @discardableResult function as a closure to another function that will run it and return the value, the resulting value should retain the information that it is discardable. At the moment, I am forced to do this:

_ = wrapper(generateDiscardableValue)
4 Likes

I think @ignorableResult is probably the clearest, and implies exactly what it does.

6 Likes

This would be nice:

func foo() -> ignorable Foo { ... }
func foo() -> some ignorable Foo { ... }
func foo() -> any ignorable Foo { ... }

Using attributes like @discardableResult and @ignorableResult gets a bit wordy, considering how often functions have discardable results in some situations (for example, method-chaining APIs).

Folks, this thread isn't about redesigning the syntax of @discardableResult.

The topic is: does the clash between two uses of "discard" cause confusion, and if so, which of the conflicting uses should be renamed and to what?

6 Likes

The original SE-390 proposal called it “forget”. For the second review we renamed it to “discard”. I briefly searched both threads and didn’t spot any bike-shedding for the name. I don’t recall why we changed the name, either.

But, I think “forget” is rather vague as to what will happen to the value. It doesn’t suggest the value is destroyed at all.

I guess @discardableResult on a function f could be confused as meaning you can write discard f() to “discard” the returned value explicitly, but you can’t. In fact, you can’t use discard on anything other than self.

1 Like

it would be less confusing, if the first page of search results for swift discard keyword didn’t consist entirely of articles about @discardableResult, with one reference to DiscardingTaskGroup thrown in.

i personally am not confused by it, but i am not the audience to be concerned about. i think unless they go spelunking down TSPL, a new user has a low chance of learning the difference.

Indeed, a good point.

Reassuringly, though, given @kavon's reminder that we can only discard self, the query swift "discard self" leads to extremely relevant results, and I think it's not too out the box to think that a user might just google that entire statement if they see only clearly irrelevant results with their first search.

2 Likes

Since noncopyable types are an advanced and rarely-used feature (for now), I think it’s much more likely that a user will know what @discardableResult is but won’t know what discard self is. In that case, the user may guess that discard self is simply sugar for _ = self, similar to Rust’s std::mem::drop.

1 Like

This is another good reason to use a term other than discard — DiscardingTaskGroup behaves nothing like the discard self statement.

3 Likes

Sorry to state the obvious but the topic's subject suggests changing @discardableResult spelling as one of the options...

I think there's a chance that it might be worthwhile at some point to add linear types to the language, which are types whose values, alongside not being implicitly copyable, also aren't implicitly destroyable. The name of a protocol denoting the ability to be implicitly destroyed, such as Discardable, should probably be consistent with the spelling of @discardableResult. If so, it may become a further rationale for changing the discard operator to something else.