[swift-evolution] ed/ing, InPlace, Set/SetAlgebra naming resolution

David Owens II david at owensd.io
Fri Feb 12 10:47:25 CST 2016


+1 to this direction. This is correct version of what I was alluding with my ill-thougthout post from last night.

I'm not 100% convinced on the `.=` operator, but I really like the rest.

This would seem like a good win for updates to libraries as well. A library vendor could add an `@inplace` version, and your code could get better performance without changing your API surface.

Also, to me, it has a nice conceptual parity to copy-on-write semantics. 

-David


> On Feb 11, 2016, at 11:26 PM, Greg Parker via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
>> On Feb 11, 2016, at 10:05 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>>> on Thu Feb 11 2016, Xiaodi Wu <swift-evolution at swift.org> wrote:
>>> 
>>> Understandable. FWIW, if one believes in autocomplete, superscript
>>> equal sign is already a valid identifier head character (per
>>> documentation and experimentation in a playground). So, if the gist of
>>> the proposal is acceptable, one can already name a pair of functions
>>> union() and union=() if the "=" is replaced with its superscript (and
>>> for that matter, =union(), but autocomplete might not help with that
>>> one). 
>> 
>> Hmm, use the fullwidth equal sign; it reads better, and compiles:
>> 
>> mutating func =union(other: Self) { ... }
>> 
>> Heh, that is awesome; we could do some real fun proofs-of-concept for
>> the proposal using that trick.  The autocomplete problem can/should be
>> fixed by tooling.
> 
> Now y'all are approaching the syntax of a proposal I made long ago for a .= operator. Here's what I wrote then (with a handful of syntax updates).
> 
> "
> 
> I suggest eliminating "…InPlace" as follows:
> 1. Use the same method name for value-creating methods and in-place mutation methods. No "…InPlace" suffix.
> 2. Write all client code syntactically as if the in-place implementations did not exist. Rely on the compiler to choose the in-place implementation when possible.
> 3. Add a new operator .= for in-place modification, to shorten the "expr = expr.method()" case.
> 
> 
> 1. Use the same method name for value-creating methods and in-place mutation methods
> 
> struct String {
>   func upper() -> String { ... }  // value-creating / out-of-place implementation
>   @inplace func upper() { ... }   // in-place implementation
> }
> 
> struct String2 {
>   @inplace func upper() { ... }   // in-place implementation
> }
> 
> The value-creating implementation is optional. If it is not present, the compiler will generate a default value-creating implementation that copies the object and calls the in-place implementation. There is no default in-place implementation; if there is no in-place implementation of a value-creating method then the compiler simply fails to optimize to it.
> 
> 
> 2. Write all client code syntactically as if the in-place implementations did not exist.
> 
> Instead of this
>   s.upperInPlace()
> write this
>   s = s.upper()
> 
> The compiler optimizer can choose the in-place upper() implementation if it is present.
> 
> Instead of this 
>   t = s.upper().trim().truncate(toLength: 5)                // oops, there's an extra copy here
>   t = s.upper().trimInPlace().truncateInPlace(toLength: 5)  // oops, compile error
> write this
>   t = s.upper().trim().truncate(toLength: 5)
> 
> The developer can chain methods together and let the compiler optimizer choose which in-place implementations to use. In this case, if all in-place implementations are available, it should call value-creating upper() followed by in-place trim() and in-place truncate(toLength:).
> 
> 
> 3. Add operator .= for in-place modification.
> 
> Operator .= is analogous to arithmetic operators like += . It is shorthand for `expr = expr.stuff` for the case where `expr` is inconveniently long. (It also doesn't evaluate `expr` twice, if Swift's optimization rules otherwise would allow it or require it for the longhand case.)
> 
> s .= upper()  
> // like s = s.upper()
> 
> p .= next
> // like p = p.next
> 
> some().long().expression .= upper().trim().truncateToLength(5)
> // like some().long().expression = some().long().expression.upper().trim().truncateToLength(5)
> 
> As seen in this last example, one advantage of this syntax is that it allows chained mutations but cleanly separates the "lookup" calls from the "mutate" calls. This is an improvement upon language and API designs with mutating methods where the property being changed is buried in the middle of the expression somewhere.
> 
> some().long().expression.upperInPlace().trimInPlace().truncateInPlace(toLength: 5)
> some().long().expression().upper.trimInPlace().truncateInPlace(toLength: 5)
> 
> some().long().expression .= upper().trim().truncate(toLength: 5)
> some().long().expression().upper .= trim().truncate(toLength: 5)
> 
> 
> One consequence of these changes is that compiler optimizations to take advantage of in-place implementation are much more important for performance, because there isn't any syntax to call the in-place implementation directly.
> 
> "
> 
> 
> -- 
> Greg Parker     gparker at apple.com     Runtime Wrangler
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list