[swift-evolution] Syntax extensions for indicating mutation (was: [Review] SE-0023 API Design Guidelines)

Haravikk swift-evolution at haravikk.me
Fri Jan 29 15:11:58 CST 2016

> 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? 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, 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 */ }

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160129/35901bc5/attachment.html>

More information about the swift-evolution mailing list