Ed/ing, InPlace, Set/SetAlgebra naming resolution

I would be strongly against this.

Void is simply an empty tuple type, and it's extremely important that an empty tuple remain storable as a value (for example, if building a promises framework, being able to use Task<Void> to denote a task that has no consumable result).

I'd also argue that if following (at least cocoa) naming conventions, the non-mutating function would be bySorting() or something similar, and not actually an issue of type inference.

Just my 2¢.

···

--
Richard

On Feb 12, 2016, at 2:11 PM, Evan Maloney via swift-evolution <swift-evolution@swift.org> wrote:

With a little tweak to Swift's type inference with respect to return values, you could provide two parallel signatures for in-place/not-in-place variants.

Imagine a FakeSortable that provided two sort() functions, one in-place and one not:

struct FakeSortable
{
   private var sortMe: [Int]

   init() { sortMe = [3, 5, 4, 2, 1] }
   init(_ sort: FakeSortable) { sortMe = sort.sortMe }

   mutating func sort()
   {
       print("sorting in place")

       sortMe = [1, 2, 3, 4, 5]
   }

   func sort() -> FakeSortable
   {
       print("returning new FakeSortable")

       var sort = FakeSortable(self)
       sort.sort() as Void
       return sort
   }
}

The thing that makes it unwieldy is that Swift can't infer the return type correctly without explicit help.

As a result, you have to call the in-place sort like this:

var toSort = FakeSortable()
toSort.sort() as Void

...and you have to call the sort-that-returns-a-new-instance as:

var another: FakeSortable = toSort.sort()

or as:

var another = toSort.sort() as FakeSortable

It seems to be Swift should be able to disambiguate purely based on the return, given that:

1. There are only two return types
2. One of them is a Void type
3. The other return supplies a value

Therefore, if one call assigns the return value and the other does not, Swift should figure out what to call unambiguously.

If I call "toSort.sort()" with no l-value to assign the return to, Swift should figure out that I'm calling the variant that returns Void.

Conversely, if I call sort() and assign the result to something, Swift should assume I'm _not_ calling the Void variant.

If Swift were able to do this, it might be feasible to use the same name for the in-place and not-in-place variants of things like sort() and not have things look ugly at the call-site.

Whether or not that is a good idea, is another discussion :)

Evan

On Feb 12, 2016, at 12:20 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Feb 11, 2016, at 11:26 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

3. Add a new operator .= for in-place modification, to shorten the "expr = expr.method()" case.

.= doesn’t really make sense in the context of Swift. Proposal’s like the (obsolete and unlikely to happen) inplace proposal work by making the = part of the name. This is important because methods (including the in place assignment operations) should be curryable.

IOW, the Equal is part of the name of the method, it isn’t part of the “operation of calling the method”.

That said, as Dave mentioned before, we discussed this extensively in the Swift 2 timeframe because it introduces yet-another concept very similar but different to the existing “mutating” keyword, and doesn’t have obvious semantics for classes. After trying very hard to make something like it work, we agreed that it was better to put the complexity of this back into the space of naming, rather than adding confusing new language features.

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

IMO, using the converb/gerund/participle (whatever you call it) here
is a terrible idea (I say that as someone with a PhD in linguistics :)
). It appears very counter-intuitive to me that ‘union’ should be the
in-place version, as it goes agains any convention I am aware of. I’d
rather just keep InPlace here or, as Greg suggests, rely on compiler
optimisations.

FWIW, I think it's almost impossible for compler optimizations to help
with arbitrarily complex LHS expressions such as a[b].c.d[e] =
a[b].c.d[e].union(f)

...and then you have the readability problem of repeated code.

I don’t think that the problem is that complicated: if the compiler detects that the invoked member has a in-place version, it just needs to check that the expression ASTs on the left and right side are identical (and that no getters have side effects). In the end, its just a special case of CSE, but its also true that Swift does not seem to do anything like this right now.

···

On 12 Feb 2016, at 17:29, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Fri Feb 12 2016, Taras Zakharko <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

— Taras

On 12 Feb 2016, at 08:43, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

I could get behind that. At the call site there would be little
visible difference between this and the alternative where functions
beginning with "=" are allowed. One I can think of would be that the
`.=` operator would require some instances (of classes that have
properties that are reference types) declared with `let` to be
declared with `var`.

On Fri, Feb 12, 2016 at 1:26 AM, Greg Parker via swift-evolution >>> <swift-evolution@swift.org> wrote:

On Feb 11, 2016, at 10:05 PM, Dave Abrahams via swift-evolution >>>>> <swift-evolution@swift.org> wrote:

on Thu Feb 11 2016, Xiaodi Wu <swift-evolution@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@apple.com Runtime Wrangler

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

+1 to '&.' or a new member accessor for mutating types. We've spent this
long arguing semantics about ing/ed just for "union", we're not going to
find a generalised and concise solution using an English suffix.

I don't think the static method is necessary, just make mutating methods
require '&.'.

Set.union would already have the type:
    (inout Set) -> Set -> Set
I think this is good.

+1 to adding mutating to reference types, thus allowing '&.' on them. I've
often thought it would be nice to have mutation checks on reference types.
Purely for better assurances about what my code can do.

···

On Saturday, 13 February 2016, David Owens II via swift-evolution < swift-evolution@swift.org> wrote:

I kinda get where your coming from, but this really seems like a calling
convention problem. You can have two functions that are nearly identical
with the *only* difference being the modification of `self` versus
returning a copy.

If we are really going to try and use a name, the suffix `InPlace` is
atleast *always* consistent and never ambiguous, unlike nearly every
attempt at using different pairs of noun and verb forms.

If we are willing to treat the calling syntax differently, then I think we
can at least come up with a non-ambigous form. I think it even applies more
generally throughout the language.

The two function signatures are this:

    func union(other: Self) -> Self
    mutating func union(other: Self) -> Self

However, the mutating version is now just syntactical short-hand for this:

    static func union(inout this: Self, _ other: Self) -> Self

This changes the language to **not** allow a mutating function to be
called with the “.” operator; after all, it’s really a static member now.

At the call site, you’d have the following:

    var a: Set<Int> = [1, 2]
    let b: Set<Int> = [3, 4]

    a.union(b) // this is *always* the non-mutating one

    Set.union(&a, b) // normal syntax for static methods, mutates `a`
    a&.union(b) // streamlined calling syntax, mutates `a`

    b&.union(a) // error: Cannot using mutating member on immutable
value ‘b’.

This model works with class types as well, but suffers from all of the
same limitations today with regards to the ability to enforce member
mutation.

This brings two language changes:

1. Any function can be declared with the mutating modifier. This is
syntactic sugar for a static function with the first parameter being an
`inout` of Self. This works for both value and reference types.
2. Any static function that has an unlabeled `inout` parameter of `Self`
can be invoked with a short-hand syntax of `&.` instead of the full static
calling form.

Maybe there are some other limitations with this approach that I’m not
thinking of at the moment.

-David

On Feb 12, 2016, at 9:20 AM, Chris Lattner via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

On Feb 11, 2016, at 11:26 PM, Greg Parker via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:

3. Add a new operator .= for in-place modification, to shorten the "expr =
expr.method()" case.

.= doesn’t really make sense in the context of Swift. Proposal’s like the
(obsolete and unlikely to happen) inplace proposal work by making the =
part of the name. This is important because methods (including the in
place assignment operations) should be curryable.

IOW, the Equal is part of the name of the method, it isn’t part of the
“operation of calling the method”.

That said, as Dave mentioned before, we discussed this extensively in the
Swift 2 timeframe because it introduces yet-another concept very similar
but different to the existing “mutating” keyword, and doesn’t have obvious
semantics for classes. After trying very hard to make something like it
work, we agreed that it was better to put the complexity of this back into
the space of naming, rather than adding confusing new language features.

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>
https://lists.swift.org/mailman/listinfo/swift-evolution

Can you write both a mutating implementation and a non-mutating implementation of the same function with this scheme? Being able to provide both is important for performance.

···

On Feb 12, 2016, at 9:18 PM, David Owens II <david@owensd.io> wrote:

I kinda get where your coming from, but this really seems like a calling convention problem. You can have two functions that are nearly identical with the *only* difference being the modification of `self` versus returning a copy.

If we are really going to try and use a name, the suffix `InPlace` is atleast *always* consistent and never ambiguous, unlike nearly every attempt at using different pairs of noun and verb forms.

If we are willing to treat the calling syntax differently, then I think we can at least come up with a non-ambigous form. I think it even applies more generally throughout the language.

The two function signatures are this:

    func union(other: Self) -> Self
    mutating func union(other: Self) -> Self

However, the mutating version is now just syntactical short-hand for this:

    static func union(inout this: Self, _ other: Self) -> Self

This changes the language to **not** allow a mutating function to be called with the “.” operator; after all, it’s really a static member now.

At the call site, you’d have the following:

    var a: Set<Int> = [1, 2]
    let b: Set<Int> = [3, 4]

    a.union(b) // this is *always* the non-mutating one
    
    Set.union(&a, b) // normal syntax for static methods, mutates `a`
    a&.union(b) // streamlined calling syntax, mutates `a`

    b&.union(a) // error: Cannot using mutating member on immutable value ‘b’.

This model works with class types as well, but suffers from all of the same limitations today with regards to the ability to enforce member mutation.

This brings two language changes:

1. Any function can be declared with the mutating modifier. This is syntactic sugar for a static function with the first parameter being an `inout` of Self. This works for both value and reference types.
2. Any static function that has an unlabeled `inout` parameter of `Self` can be invoked with a short-hand syntax of `&.` instead of the full static calling form.

Maybe there are some other limitations with this approach that I’m not thinking of at the moment.

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler

continued thought….

I am wondering if part of my issue is that there is also an inherent difference between bare to the metal “collection” operations and those of higher-level collections.

i.e. defining SetAlgebra (which infers higher level collections) based on low level requirements for “in place” mutations (for performance reasons) while trying to also satisfy the immutable “requirements” of higher level collections.

Trying to satisfy two really different objectives through the same interface - makes both seem a like a kludge — and will eventually have to be refactored…. but at greater cost down the road.

I don’t think any language really did a good job of implementing collections or defining overall collection behaviour - the first time around.

Which leads me to — if the decision is to stay away from math terms of art because it really does not fit, then maybe also staying away from using “Algebra” in the title might also lessen the discomfort.

People might actually think they have to implement “SetAlgebra” on real mathematical collections :p

···

On 2016-02-16, at 3:57:02, Craig Cruden <ccruden@novafore.com> wrote:

It does seem to me that there is seriously wrong - when you are literally taking a sledge-hammer to try and make standard mathematical terminology (square peg) fit into a given proposal (round hole).

When you are at a point where you are taking a sledgehammer to make a square peg fit into a round hole, then it might be a sign that it won’t fit.

I have less issues with “InPlace” than other proposals so far - it makes mutable operations second class citizens (instead of the other way around).

I still think that the having two copies of every operation on a single type - is sort of the schizophrenic version of interface design — which is leading collections down the path of being less concise of what it’s function is. Giving the same collection two completely identities within the same body.

On 2016-02-16, at 3:46:07, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On that topic, you mentioned earlier that you've asked someone involved in the decision to explain why we can't have a term-of-art InPlace exception. That would be enormously beneficial as it seems we've returned once again to: "InPlace isn't so bad"!

It's difficult to advance alternatives clearly superior to InPlace while the objection to its use in this context originating from the Inner Sanctum of Swiftiness[TM] remains opaque.

On Mon, Feb 15, 2016 at 2:32 PM Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

on Mon Feb 15 2016, Austin Zheng <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> +1. Would rather see us retain the (IMHO) correct math-based nomenclature,
> and come up with rules for handling cases where there are 'terms of art'
> that don't fit neatly into the standard ruleset.

Of course, that's what "InPlace" was supposed to do.

>
> Austin
>
> On Mon, Feb 15, 2016 at 11:46 AM, Xiaodi Wu via swift-evolution < >> > swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>> It pains me that well-known math terms and even whole protocols get lopped
>> off because of vagaries of the English language. New thought prompted by
>> some of these suggestions:
>>
>> There's a fairly circumscribed number of commonly used mathematical terms
>> of art. These describe for the most part functions for which there are no
>> noun/verb pairs. Suppose then, we have a rule:
>>
>> Define these mathematical functions only outside types, as though they
>> were operators. If (as it seems), operators are an acceptable option for
>> Set but for the nomenclature, surely these functions can be acceptable as
>> well. Then you would have:
>> union(a, b) // non-mutating
>> union(&a, b) // mutating
>>
>> This is unambiguous, terse, conformant to expectations arising from
>> familiarity with math, and recognizably English, and you can still have a
>> SetAlgebra protocol if it can ensure these functions exist for conforming
>> types as Equatable ensures ==. "Pollution" of the global scope would be
>> limited to commonly used math terms, which should not be coopted for
>> another purpose in any case.
>>
>>
>>
>>
>>
>>
>>
>> On Mon, Feb 15, 2016 at 1:17 PM Dave Abrahams via swift-evolution < >> >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>>>
>>> on Mon Feb 15 2016, Xiaodi Wu <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> > Agreed that "union" creates an expectation that it's non-mutating.
>>> >
>>> > There's no real point in pushing back on whether UIs are more or less
>>> > important for Swift than math.
>>> >
>>> > Problem is, the moment you name something SetAlgebra, you've set user
>>> > expectations that it's a 'math API'. Those ain't UI terms.
>>>
>>> Yep. As I mentioned in
>>> <
>>> http://news.gmane.org/find-root.php?message_id=m2pow033r1.fsf%40eno.apple.com <http://news.gmane.org/find-root.php?message_id=m2pow033r1.fsf%40eno.apple.com&gt;
>>> >,
>>> we have a semantic muddle here. Given where this is all headed, I am
>>> somewhat inclined to retire the SetAlgebra protocol (it only seems to
>>> have 3-4 uses on github), but renaming it could be another viable
>>> option.
>>>
>>> > On Mon, Feb 15, 2016 at 11:25 AM Dave Abrahams via swift-evolution < >> >>> > swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> >
>>> >>
>>> >> on Mon Feb 15 2016, Maximilian Hünenberger <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >> >>> >> wrote:
>>> >>
>>> >> > I also prefer (2). Isn't "union", "intersection", ... a "Term of
>>> Art"?
>>> >> > See the guidelines under "Stick to the established meaning".
>>> >> >
>>> >> > So we should stick to the mathematical naming.
>>> >>
>>> >> My understanding of the rationale for the current direction is that the
>>> >> domain of building GUI apps is more important than that of math, so the
>>> >> look and feel of sets should match those of most other (non-math) APIs.
>>> >>
>>> >> > Since these terms almost always return a new instance we should have
>>> >> > an obvious mutating version with an "inPlace" suffix.
>>> >> >
>>> >> > - Maximilian
>>> >> >
>>> >> >> Am 14.02.2016 um 22:37 schrieb Xiaodi Wu via swift-evolution
>>> >> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
>>> >> >>
>>> >> >> From a 10,000-ft view, I'd suggest that the noun/verb rule
>>> >> >> consistently runs into a problem with mathematical terms.
>>> >> >>
>>> >> >> In general, mathematical functions don't have verb forms. You
>>> >> >> 'compute' the reciprocal, or 'find' the reciprocal, or 'take' the
>>> >> >> reciprocal, you don't 'reciprocate' or 'reciprocalize'. Likewise for
>>> >> >> trigonometric functions, etc. Nor can you really 'cross produce'...
>>> >> >>
>>> >> >> So consistent is this trend that where two words might be noun/verb
>>> >> >> counterparts, like intersect/intersection and
>>> >> >> transform/transformation, common math usage treats both as
>>> >> >> acceptable nouns.
>>> >> >>
>>> >> >> In colloquial usage, you might verb the noun, but then by definition
>>> >> >> the verb and noun become the same. Then, to generate a noun
>>> >> >> phrase/participle/etc. that looks different from the verb, you have
>>> >> >> to noun-ify the verbed noun.
>>> >> >>
>>> >> >> Without an exception for mathematical function names, the only
>>> >> >> solution to fulfill these new Swift rules are clobbering the
>>> >> >> well-known math name or not using the math name at all. Indeed all
>>> >> >> proposed solutions so far come down to one of four options, either
>>> >> >> applied globally or only to sets for now, punting the rest down the
>>> >> >> road:
>>> >> >>
>>> >> >> (1) Abandon the rule, making a new one (e.g.: .=)
>>> >> >> (2) Make an exception to the rule for math function names
>>> >> >> (3) Generate the least offensive noun-ified verbed nouns based on
>>> math
>>> >> function names
>>> >> >> (4) Don't use math function names
>>> >> >>
>>> >> >> (1) is off the table, according to the core team. My vote at this
>>> >> >> point is for (2), and I see that a few others have voiced that
>>> >> >> opinion. It'd be nice to get a sense from the core team if that is
>>> >> >> even a possibility. (3) has elicited a lot of discussion and
>>> >> >> visceral reactions. (4) might be workable for sets alone but surely
>>> >> >> can't be a generalized solution for all mathematical concepts to be
>>> >> >> encountered in Swift.
>>> >> >> On Sun, Feb 14, 2016 at 3:14 PM Tyler Fleming Cloutier via >> >>> >> >> swift-evolution >> >>> >> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> >> >>>> On Feb 14, 2016, at 12:48 PM, Dave Abrahams >> >>> >> >>>> <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:
>>> >> >>>>
>>> >> >>>>
>>> >> >>>> on Sun Feb 14 2016, Tyler Fleming Cloutier >> >>> <cloutiertyler-AT-aol.com <http://cloutiertyler-at-aol.com/&gt;&gt; >> >>> >> wrote:
>>> >> >>>>
>>> >> >>>>>> On Feb 14, 2016, at 8:27 AM, Dave Abrahams >> >>> >> >>>>>> <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:
>>> >> >>>>>>
>>> >> >>>>>>
>>> >> >>>>>> on Sat Feb 13 2016, Tyler Fleming Cloutier >> >>> >> <cloutiertyler-AT-aol.com <http://cloutiertyler-at-aol.com/&gt;&gt; wrote:
>>> >> >>>>>>
>>> >> >>>>>>> I would, personally, be very careful about discarding the
>>> >> mathematical
>>> >> >>>>>>> terms since they are so widely used and understood.
>>> >> >>>>>>
>>> >> >>>>>> IMO it's better to leave them aside than to use them in
>>> “creative”
>>> >> ways
>>> >> >>>>>> that might be misleading.
>>> >> >>>>>
>>> >> >>>>> Agreed. I’m all for that.
>>> >> >>>>>
>>> >> >>>>>>> One issue is that it’s going to be hard to search for the
>>> >> operation I
>>> >> >>>>>>> want considering I won’t be looking for "func
>>> >> >>>>>>> invertingMembershipOfContentsOf(other: Self) -> Self”. I’m
>>> >> concerned
>>> >> >>>>>>> people are going to have to do mental gymnastics to build the
>>> map
>>> >> from
>>> >> >>>>>>> math term to Swift function every time they want to look for a
>>> set
>>> >> >>>>>>> operation method. “func invertingMembershipOfContentsOf(other:
>>> >> Self)
>>> >> >>>>>>> -> Self” doesn’t exactly seem to fit in the commonly held Venn
>>> >> diagram
>>> >> >>>>>>> mental model of set operations. You could always have a
>>> >> documentation
>>> >> >>>>>>> comment that specifies the mathematical term so that people
>>> didn’t
>>> >> >>>>>>> have to double check themselves every time.
>>> >> >>>>>>>
>>> >> >>>>>>> That being said, if the autocomplete issue is not a concern,
>>> I’m of
>>> >> >>>>>>> the opinion that the names Ricardo proposed are short, clear,
>>> and
>>> >> are
>>> >> >>>>>>> not so hard to fit to my Venn diagram mental model.
>>> >> >>>>>>
>>> >> >>>>>> +1
>>> >> >>>>>>
>>> >> >>>>>>> However, I tend to think that if there has to be this much
>>> dancing
>>> >> to
>>> >> >>>>>>> name a set of fundamental operations, the guidelines aren’t
>>> >> >>>>>>> accomplishing their goal.
>>> >> >>>>>>
>>> >> >>>>>> I can't disagree.
>>> >> >>>>>>
>>> >> >>>>>>> It’s going to make it that much harder for people do design
>>> their
>>> >> own
>>> >> >>>>>>> APIs. I'm having quite a time trying to conform Mattt’s Surge
>>> API
>>> >> to
>>> >> >>>>>>> the guidelines.
>>> >> >>>>>>
>>> >> >>>>>> Please explain in detail. Without details we don't know what's
>>> >> wrong
>>> >> >>>>>> with the guidelines.
>>> >> >>>>>
>>> >> >>>>> Ah, I apologize. I’ve gone into detail about this API on the list
>>> >> >>>>> before, but I should have included the details here.
>>> >> >>>>>
>>> >> >>>>> Here are my previous posts:
>>> >> >>>>>
>>> >>
>>> [swift-evolution] [Review] SE-0023 API Design Guidelines
>>> >> >>>>> <
>>> >>
>>> [swift-evolution] [Review] SE-0023 API Design Guidelines
>>> >> >
>>> >> >>>>>
>>> >> >>>>> Basically the issues come down to the following. The Accelerate
>>> >> >>>>> framework typical operates in a non-mutating way. This means
>>> that my
>>> >> >>>>> API only has non mutating member functions and I should use the
>>> >> ed/ing
>>> >> >>>>> rule according to the guidelines to name my methods.
>>> >> >>>>>
>>> >> >>>>> This is very difficult for some methods. I’m able to frequently
>>> get
>>> >> >>>>> around the problem for things like “sin” or “arctan” by keeping
>>> them
>>> >> >>>>> as global functions, but I can’t do that for a number of
>>> >> >>>>> methods. Consider:
>>> >> >>>>>
>>> >> >>>>> remainder
>>> >> >>>>> dot (returns a scalar, thus there can’t be a mutating version, so
>>> >> >>>>> should I just call it dot? Guidelines don’t really comment on
>>> this)
>>> >> >>>>> mean (same as above)
>>> >> >>>>> cross
>>> >> >>>>> reciprocal
>>> >> >>>>> threshold
>>> >> >>>>> copysign
>>> >> >>>>> fastFourierTransform
>>> >> >>>>> pow (arguably the method version should be called raisedTo)
>>> >> >>>>>
>>> >> >>>>> I could force all these to be global functions only, but these
>>> are
>>> >> not
>>> >> >>>>> as cut and dry as “sin” or “arctan”. I feel like I’d be
>>> splitting my
>>> >> >>>>> API up into two parts just based on the fact that it’s difficult
>>> to
>>> >> >>>>> use the ed/ing rule. That makes it very difficult for users to
>>> find
>>> >> >>>>> certain functions in my API.
>>> >> >>>>>
>>> >> >>>>> In this case there are no corresponding mutating operations
>>> because
>>> >> of
>>> >> >>>>> the way Accelerate works, but one could certainly imagine an API
>>> with
>>> >> >>>>> mutating counterparts. The way I read the guidelines, they seem
>>> to
>>> >> >>>>> imply I should use ed/ing regardless of whether there is a
>>> mutating
>>> >> >>>>> counterpart. I’d love to hear your thoughts on this.
>>> >> >>>>
>>> >> >>>> As long as the ones without side effects read as noun phrases and
>>> the
>>> >> >>>> ones with side-effects read as verb phrases, you're good. No
>>> ed/ing
>>> >> >>>> needed.
>>> >> >>>
>>> >> >>> Ah yes, you are very right. Still what would the mutating versions
>>> >> >>> of remainder, fastFourierTransform, or reciprocal be? getRemainder?
>>> >> >>> applyFastFourierTransform? reciprocate? I suppose those aren’t so
>>> >> >>> bad.
>>> >> >>>
>>> >> >>> I also suppose cross could become x.crossProduct(with: y) and
>>> >> >>> copysign, x.copyingSign(of: y). Seems a little verbose, but it does
>>> >> >>> the job.
>>> >> >>>
>>> >> >>> Thanks,
>>> >> >>>
>>> >> >>> Tyler
>>> >> >>>
>>> >> >>>
>>> >> >>>>
>>> >> >>>>>
>>> >> >>>>>
>>> >> >>>>> Thanks,
>>> >> >>>>>
>>> >> >>>>> Tyler
>>> >> >>>>>
>>> >> >>>>>>
>>> >> >>>>>>>
>>> >> >>>>>>> Tyler
>>> >> >>>>>>>
>>> >> >>>>>>>> On Feb 13, 2016, at 9:09 PM, Ricardo Parada via >> >>> >> >>>>>>>> swift-evolution >> >>> >> >>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> >> >>> >> >>>>>>>> wrote:
>>> >> >>>>>>>>
>>> >> >>>>>>>> Hi Dave,
>>> >> >>>>>>>>
>>> >> >>>>>>>> I would be okay with staying away from the mathematical terms
>>> >> >>>>>>>> similar to what you are suggesting except that the union can
>>> still
>>> >> >>>>>>>> be made more concise if you use merged / merge for the base
>>> name
>>> >> and
>>> >> >>>>>>>> shorten the labels to a bare minimum without loosing
>>> clarity. In
>>> >> >>>>>>>> addition, the merge can have a second parameter with a
>>> default to
>>> >> >>>>>>>> false in order to implement the symmetric difference
>>> >> >>>>>>>> (a.k.a. exclusive or). Recall that symmetric difference is
>>> the
>>> >> >>>>>>>> union of two sets and then removing the intersection (or
>>> members
>>> >> in
>>> >> >>>>>>>> common). I think it looks perfect (concise and clear). What
>>> does
>>> >> >>>>>>>> everybody else think?
>>> >> >>>>>>>>
>>> >> >>>>>>>> Non-mutable
>>> >> >>>>>>>>
>>> >> >>>>>>>> let union = a.merged(with: b)
>>> >> >>>>>>>> let intersection = a.members(in: b)
>>> >> >>>>>>>> let difference = a.removingMembers(in: b)
>>> >> >>>>>>>> let symmetricDifference = a.merged(with: b,
>>> >> removingMembersInCommon: true)
>>> >> >>>>>>>>
>>> >> >>>>>>>> Mutable (In-Place)
>>> >> >>>>>>>>
>>> >> >>>>>>>> a.merge(with: b) // union in-place
>>> >> >>>>>>>> a.removeMembers(notIn: b) // intersect in-place
>>> >> >>>>>>>> a.removeMembers(in: b) // difference in-place
>>> >> >>>>>>>> a.merge(with: b, removeMembersInCommon: true) // symmetric
>>> >> difference in-place
>>> >> >>>>>>>>
>>> >> >>>>>>>> Ricardo Parada
>>> >> >>>>>>>>
>>> >> >>>>>>>>
>>> >> >>>>>>>>> On Feb 13, 2016, at 1:16 PM, Dave Abrahams via >> >>> swift-evolution >> >>> >> >>>>>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> >>> >> >>>>>>>>> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> >> >>> >> >>>>>>>>> wrote:
>>> >> >>>>>>>>>
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> on Fri Feb 12 2016, Ricardo Parada < >> >>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> >>> >> >>>>>>>>> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>> wrote:
>>> >> >>>>>>>>>
>>> >> >>>>>>>>>> Hi all,
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> I can’t make up my mind. Let me propose two different
>>> >> alternatives
>>> >> >>>>>>>>>> that I’m not sure if they have been considered:
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> ALTERNATIVE 1
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Non-mutable (noun-based)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func union(other: Self) -> Self
>>> >> >>>>>>>>>> + func union(other: Self) -> Self Assumes union
>>> is a
>>> >> noun, i.e. not a verb
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func intersect(other: Self) -> Self
>>> >> >>>>>>>>>> + func intersection(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func subtract(other: Self) -> Self
>>> >> >>>>>>>>>> + func subtraction(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func exclusiveOr(other: Self) -> Self
>>> >> >>>>>>>>>> + func symmetricSubtraction(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Mutable (verb-based)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func unionInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func unite(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func intersectInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func intersect(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func subtractInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func subtract(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func exclusiveOrInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func symmetricSubtract(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Comments:
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> With this alternative we keep the union name which I assume
>>> is
>>> >> >>>>>>>>>> popular. However, one has to accept unite as a verb (for
>>> the
>>> >> mutable
>>> >> >>>>>>>>>> version) as I wanted all the mutable methods use verbs for
>>> >> >>>>>>>>>> consistency. I think unite is acceptable because it can be
>>> >> found in
>>> >> >>>>>>>>>> the dictionary and it is a verb.
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Notice that all the non-mutable methods use nouns: union,
>>> >> >>>>>>>>>> intersection, subtraction and symmetricSubtraction.
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> I understand some may oppose to symmetricSubtraction saying
>>> that
>>> >> >>>>>>>>>> symmetricSubraction is not as common as "exclusive or".
>>> >> However,
>>> >> >>>>>>>>>> using symmetricSubtraction is consistent with subtraction
>>> and
>>> >> it hints
>>> >> >>>>>>>>>> to a variation of the “subtraction" operation. We will get
>>> >> used to it
>>> >> >>>>>>>>>> quickly / easily.
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> The mutable methods all use verbs: unite, intersect,
>>> subtract
>>> >> and symmetricSubtract.
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> ALTERNATIVE 2
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Non-mutable
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func union(other: Self) -> Self
>>> >> >>>>>>>>>> + func adding(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func intersect(other: Self) -> Self
>>> >> >>>>>>>>>> + func intersecting(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func exclusiveOr(other: Self) -> Self
>>> >> >>>>>>>>>> + func exclusiveOring(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - func subtract(other: Self) -> Self
>>> >> >>>>>>>>>> + func removing(other: Self) -> Self
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Mutable
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func unionInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func add(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func intersectInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func intersect(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func exclusiveOrInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func exclusiveOr(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> - mutating func subtractInPlace(other: Self)
>>> >> >>>>>>>>>> + mutating func remove(other: Self)
>>> >> >>>>>>>>>>
>>> >> >>>>>>>>>> Comments: This alternative gives up on union in favor or
>>> add.
>>> >> Many
>>> >> >>>>>>>>>> may not like this, that is why I have it as the second
>>> >> alternative.
>>> >> >>>>>>>>>> It brings back exclusiveOr and treats it as a verb. Some
>>> may
>>> >> argue
>>> >> >>>>>>>>>> that exclusiveOr is a noun for the "exclusive or" operation.
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> If we are going to force Set fit the naming guidelines, I
>>> would
>>> >> prefer
>>> >> >>>>>>>>> to stay away from the mathematical terms altogether.
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> func insertingContentsOf(other: Self) -> Self
>>> //
>>> >> union
>>> >> >>>>>>>>> mutating func insertContentsOf(other)
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> func members(in other: Self) -> Self
>>> >> // intersection
>>> >> >>>>>>>>> mutating func removeMembers(notIn: other)
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> func removingMembersAndAddingNonMembers(in other: Self) ->
>>> Self
>>> >> // symmetric difference
>>> >> >>>>>>>>> mutating func removeMembersAndAddingNonMembers(in other:
>>> Self)
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> func removingMembers(in other: Self) -> Self
>>> >> // subtract
>>> >> >>>>>>>>> mutating func removeMembers(in other: Self)
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> If it would help with clarity, we could replace "in" with
>>> >> "foundIn"
>>> >> >>>>>>>>> above.
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> --
>>> >> >>>>>>>>> -Dave
>>> >> >>>>>>>>>
>>> >> >>>>>>>>> _______________________________________________
>>> >> >>>>>>>>> swift-evolution mailing list
>>> >> >>>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> >>>>>>>>> <mailto:swift-evolution@swift.org <mailto:swift-evolution@swift.org>>
>>> >> >>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >> >>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution&gt;
>>> >> >>>>>>>> _______________________________________________
>>> >> >>>>>>>> swift-evolution mailing list
>>> >> >>>>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> >>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >> >>>>>>
>>> >> >>>>>> --
>>> >> >>>>>> -Dave
>>> >> >>>>
>>> >> >>>> --
>>> >> >>>> -Dave
>>> >> >>> _______________________________________________
>>> >> >>> swift-evolution mailing list
>>> >> >>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> >>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >> >> _______________________________________________
>>> >> >> swift-evolution mailing list
>>> >> >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >> > _______________________________________________
>>> >> > swift-evolution mailing list
>>> >> > swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >>
>>> >> --
>>> >> -Dave
>>> >>
>>> >> _______________________________________________
>>> >> swift-evolution mailing list
>>> >> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> >>
>>> > _______________________________________________
>>> > swift-evolution mailing list
>>> > swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> --
>>> -Dave
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

IMO, using the converb/gerund/participle (whatever you call it) here
is a terrible idea (I say that as someone with a PhD in linguistics :)
). It appears very counter-intuitive to me that ‘union’ should be the
in-place version, as it goes agains any convention I am aware of. I’d
rather just keep InPlace here or, as Greg suggests, rely on compiler
optimisations.

FWIW, I think it's almost impossible for compler optimizations to help
with arbitrarily complex LHS expressions such as a[b].c.d[e] =
a[b].c.d[e].union(f)

...and then you have the readability problem of repeated code.

I don’t think that the problem is that complicated: if the compiler
detects that the invoked member has a in-place version, it just needs
to check that the expression ASTs on the left and right side are
identical (and that no getters have side effects).

The devil is in the parentheses, brother.

···

on Sat Feb 13 2016, Taras Zakharko <swift-evolution@swift.org> wrote:

On 12 Feb 2016, at 17:29, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:
on Fri Feb 12 2016, Taras Zakharko > >> <swift-evolution@swift.org >> <mailto:swift-evolution@swift.org>> >> wrote:

In the end, its just a special case of CSE, but its also true that
Swift does not seem to do anything like this right now.

— Taras

On 12 Feb 2016, at 08:43, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

I could get behind that. At the call site there would be little
visible difference between this and the alternative where functions
beginning with "=" are allowed. One I can think of would be that the
`.=` operator would require some instances (of classes that have
properties that are reference types) declared with `let` to be
declared with `var`.

On Fri, Feb 12, 2016 at 1:26 AM, Greg Parker via swift-evolution >>>> <swift-evolution@swift.org> wrote:

On Feb 11, 2016, at 10:05 PM, Dave Abrahams via swift-evolution >>>>>> <swift-evolution@swift.org> wrote:

on Thu Feb 11 2016, Xiaodi Wu <swift-evolution@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@apple.com Runtime Wrangler

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
<https://lists.swift.org/mailman/listinfo/swift-evolution&gt;

--
-Dave

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution
<https://lists.swift.org/mailman/listinfo/swift-evolution&gt;

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

I don't see why not.

Another way to potentially model it is like this:

    protocol UnionType {
      func union(other: Self) -> Self
      mutating func union(other: Self) -> Self
    }

Internally, each of these is basically this:

    func union(this, other: Self) -> Self
    func union(inout this, other: Self) -> Self

The above is suggesting that member functions have an implicit self parameter as the first parameter.

For value-types, it may even be possible to generate the mutating version.

To call them:

    a.union(b) // this is *always* the non-mutating one
    a&.union(b) // streamlined calling syntax, mutates `a`

-David

···

On Feb 15, 2016, at 11:11 AM, Greg Parker <gparker@apple.com> wrote:

On Feb 12, 2016, at 9:18 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

I kinda get where your coming from, but this really seems like a calling convention problem. You can have two functions that are nearly identical with the *only* difference being the modification of `self` versus returning a copy.

If we are really going to try and use a name, the suffix `InPlace` is atleast *always* consistent and never ambiguous, unlike nearly every attempt at using different pairs of noun and verb forms.

If we are willing to treat the calling syntax differently, then I think we can at least come up with a non-ambigous form. I think it even applies more generally throughout the language.

The two function signatures are this:

    func union(other: Self) -> Self
    mutating func union(other: Self) -> Self

However, the mutating version is now just syntactical short-hand for this:

    static func union(inout this: Self, _ other: Self) -> Self

This changes the language to **not** allow a mutating function to be called with the “.” operator; after all, it’s really a static member now.

At the call site, you’d have the following:

    var a: Set<Int> = [1, 2]
    let b: Set<Int> = [3, 4]

    a.union(b) // this is *always* the non-mutating one
    
    Set.union(&a, b) // normal syntax for static methods, mutates `a`
    a&.union(b) // streamlined calling syntax, mutates `a`

    b&.union(a) // error: Cannot using mutating member on immutable value ‘b’.

This model works with class types as well, but suffers from all of the same limitations today with regards to the ability to enforce member mutation.

This brings two language changes:

1. Any function can be declared with the mutating modifier. This is syntactic sugar for a static function with the first parameter being an `inout` of Self. This works for both value and reference types.
2. Any static function that has an unlabeled `inout` parameter of `Self` can be invoked with a short-hand syntax of `&.` instead of the full static calling form.

Maybe there are some other limitations with this approach that I’m not thinking of at the moment.

Can you write both a mutating implementation and a non-mutating implementation of the same function with this scheme? Being able to provide both is important for performance.

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler