Idea: mutatingForEach for Collections

My vote for the name is ".mutateEach" since that is what it does. More importantly, "mutate" is one of the first words liable to pop into the programmers head when he or she needs to use it (we all type the word "mutate" repeatedly in this language)

The name is not a big deal, but Mutate, in this language, is more memorable than Modify

If you believe it’s a mutating version of map, then the guidelines very much apply and we should name it formMap!

map is a verb in this context, not a noun. It parallels filter.

(I'm splitting hairs, but we're discussing names, so everything is splitting hairs. I already mentioned why the signature is wrong for being a map rather than a forEach.)

8 Likes

map is not functioning as a noun here, so formMap would not adhere to the naming guidelines. I guess they would tell us that we should have had map (mutating) and mapped (non-mutating), but that would be a huge violation of the "stick to the established meaning if you do use a term of art" rule, so we rightfully didn't do that.

5 Likes

As one of the two proposal authors, I'd like to politely request that we put a pin in the discussions around the naming guidelines. They dominated the previous thread, and while I like the game of linguistics as much as the next person, I'd also like to try to actually get stuff done.

I'm happy to hear name proposals, but at this stage I should stress that unless someone comes up with a really fantastic name I'll lean towards sticking with modifyEach: I don't think I've heard a proposal that is drastically better. Assuming we get to the proposal stage, I'll make it clear to the Swift Core Team that they should feel free to modify the name to something that fits the appropriate naming sensibilities of the standard library.

12 Likes

There is no need to parse this like a lawyer. The spirit and intent of the guidelines is to offer a way to create verb/noun pairs when the ā€œnounā€ (the nonmutating operation) isn’t something that can be made into a verb in a natural way.

Obviously, since the word ā€œformā€ generally precedes a noun in grammatical English, it can usually only be used with a noun. However ā€œform for eachā€ is very much grammatical and there is no reason why this rule can’t be applicable.

The guidelines don’t cover precisely every situation in the most literal sense—they’re not laws: they’re meant to guide.

It is not. 'nuff said. The relation between forEach and the new modifyEach is not even close to that between (e.g.) union and formUnion, where formUnion creates a union, and union mutates its input into the aforementioned union of sets.
forEach mutates nothing, neither does it create nothing. It only provides input for side-effects. How can forEach fit with the formSomething guideline? It cannot.

(yes, there's a need to parse it like a lawyer when one feels it's the only way to make it stick.)

1 Like

Huh?

The point I'm trying to make is that, after an extensive discussion, Swift already has a word to describe "perform this operation, but in place." Alternatives such as "in place," "emplace," "mutate," "modify" were all considered but rejected in favor of the word "form."

"to form" is a transitive verb for any sense that can be used here. "transitive" means it has a direct object. Where is the direct object? Your hypothetical "form for each" phrase has no direct object. What are we forming? Let's look at the closure: (inout Type) -> Void. Are we forming a void? Obviously not.

I believe there's also a notion of not making up nonsensical names, is there not?

The beauty of the English word "form" is that it can be used without an object, in the sense of molding or modifying the subject.

That said, there's always the option of formEach, as I suggested above, if you wish to use "form" only as a transitive verb when it comes to Swift.

Still not sure why you think it's nonsensical.

The intransitive uses do not apply here. When you don't have an explicit object there must be an implied one; the question remains: where is the object. I think you're fighting grammar here, and I don't see how it will yield. Perhaps you should form full sentences that illustrate just how well it works; I can't think of anything. What are you forming? Anything specific?

1 Like

Why must there be? Compare:

  • result.get
  • array.formForEach

And what I’m saying is precisely that the intransitive use can apply here.

Why must there be an object? Because "to form" is a transitive verb which has a direct object, stated or implied. That statement is derived from English grammar.

"get the result" (explicitly stated) or throw (implied.)

"form for each array"? Either that doesn't mean what you think it means, or you didn't say what you actually meant. I'm thinking the latter.

I would remark that you keep falling back on repetition; I'm asking for new information. If you have none, then this can stop.

  • result.get(): get the result.
  • array.formForEach { $0.formUnion(x) }: form the array, for each form union (with) x.

For me, the number of words you needed to add clearly illustrates the opposite of the point you were trying to make. Thank you.

We really need a better way to deal with naming discussions. This is completely drowning other arguments.

Maybe we can find a rule where any participant posts one comment with their suggestions (and possible short rationale), then compile a list of all suggestions and then move that to a different thread after all other issues have been discussed? (Just an idea. I am sure other people have better suggestions)

1 Like

To be fair, this is a proposal to add a single function for which the functionality is fairly uncontroversial and for which the naming is controversial.

This should be no surprise as the naming of the SetAlgebra methods was one of the most controversial threads of Swift Evolution in its first year.

While drawn out and difficult, I can’t see how one can design APIs without allowing debate over their names.

5 Likes

It seems possible to overload forEach so that the mutating one is used when possible. This is probably a bad idea.

extension MutableCollection {
  mutating func forEach(_ body: (inout Element) throws -> Void) rethrows {
    var index = self.startIndex
    while index != self.endIndex {
        try body(&self[index])
        self.formIndex(after: &index)
    }
  }
}

let array = ["A", "B", "C"]
array.forEach { // `Sequence.forEach(_:)`
  print($0)
}

var mutableArray = array
mutableArray.forEach { // `MutableCollection.forEach(_:)`
  $0 = $0.lowercased()
}
2 Likes

I had thought of that earlier, and decided not to post it because I also imagine it’s probably a bad idea.

But now that both of us think it, I’m pretty sure two bads make a good, right? :-)

4 Likes