[swift-evolution] [Review] SE-0023 API Design Guidelines (was: Syntax extensions for indicating mutation)
Dave Abrahams
dabrahams at apple.com
Fri Jan 29 18:53:38 CST 2016
on Fri Jan 29 2016, Haravikk <swift-evolution-AT-haravikk.me> wrote:
>> On 29 Jan 2016, at 20:23, Dave Abrahams via swift-evolution
>> <swift-evolution at swift.org> wrote:
>> on Fri Jan 29 2016, Adriano Ferreira <adriano.ferreira-AT-me.com> wrote:
>>
>>> Indeed, Ruby has an interesting convention where a question mark
>
>>> (?) is used for boolean functions/methods:
>>>
>>> In Swift: foo.contains(...)
>>> In Ruby: foo.include?(...)
>>>
>>> In Swift: foo.isEmpty
>>> In Ruby: foo.empty?
>>>
>>> Well, in the last case `isEmpty` is a property whereas `empty?` is
>>> a method, but the idea is similar.
>>>
>>> Also, an exclamation mark (!) is generally used to indicate that a
>>> function/method mutates `self`:
>>>
>>> Non-mutating:
>>>
>>> Swift — foo.reverse()
>>> Ruby — foo.reverse
>>>
>>> Mutating:
>>>
>>> Swift — foo.reverseInPlace()
>>> Ruby — foo.reverse!
>>>
>>> Non-mutating:
>>>
>>> Swift — foo.sort() or foo.sort({…})
>>> Ruby — foo.sort or foo.sort {…}
>>>
>>> Mutating:
>>>
>>> Swift — foo.sortInPlace() or foo.sortInPlace({…})
>>> Ruby — foo.sort! or foo.sort! {…}
>>>
>>> I think it’s a simple and nice way of addressing the naming issue of
>>> mutating vs. non-mutating or pure vs. impure
>>> functions/methods. However, this conflicts with the syntax sugar of
>>> Optionals and, therefore, following this path would have a clear
>>> impact in the language.
>>
>> Please keep discussion of new language features in a separate thread;
>> thanks.
>
> I thought the point was mostly just to highlight how another language
> has dealt with the same problem?
Presumably the person posting about this knew what the point was? ;-)
> Of course Ruby’s syntax wouldn’t be feasible in Swift, and at the same
> time I think it’s actually unnecessary to add it so long as a good
> naming convention is very clear about what something is or does,
Now we're back on topic.
> i.e-
>
> foo.sort() // Sorts the original
> foo.sorted() // Returns a sorted form of the original, leaving
> the original unchanged
>
> You could do reverseInPlace() instead, but personally I dislike that,
> though the main problem with the above is how easy it is to make a
> typo, whereas the operators for mutability would throw errors if used
> incorrectly. However, if properly declared the mutating vs
> non-mutating methods shouldn’t actually be easy to misuse either, i.e-
>
> mutating func sort() -> Void { /* Do some sorting in here */ }
> @warn_unused_result func sorted() -> SomeType { /* Make and
> return a sorted copy in here */ }
>
> The first declaration can’t be misused because with its return type
> being void trying to assign it would cause an error, plus the mutating
> keyword ensures that it won’t be intentionally called on a read-only
> value.
> The second declaration’s @warn_unused_result ensures that it won’t be
> misused because it isn’t possible to simply call it, it must be
> assigned or produce a warning. So this actually reinforces that overly
> verbose method names like reverseInPlace() are not needed when
> attempting to convey mutating vs non-mutating behaviour, as the
> compiler will quickly indicate a misuse.
>
> The main problem is when a mutating function also needs to be able to
> return some optional result in addition to mutating itself for
> example:
>
> mutating func sort() -> Int { /* Sort self, and return the number of elements that had to be relocated in order to do-so */ }
I don't see a problem here. We have precedent in, e.g.,
RangeReplaceableCollectionType:
/// Remove the element at index `i`.
///
/// Invalidates all indices with respect to `self`.
///
/// - Complexity: O(`self.count`).
mutating func removeAtIndex(i: Index) -> Generator.Element
> However I think the easiest fix in this case would be declare it like:
>
> @warn_unused_result mutating func sortAndCountElementsMoved() -> Int { /* Sort and return number of elements moved */ }
> mutating func sort() { let _ =
> self.sortAndCountElementsMoved(); } // Call the above, but explicitly
> ignore its result
>
> So eh… in conclusion, I don’t think we need Ruby’s operators as Swift
> can solve the same problems, though maybe not as succinctly.
--
-Dave
More information about the swift-evolution
mailing list