Kotlin / kotlinx.collections.immutable

Immutable persistent collections for Kotlin
Apache License 2.0
1.12k stars 56 forks source link

Naming for immutable collection modification operations #8

Open slburson opened 7 years ago

slburson commented 7 years ago

Let me also suggest my own FSet functional collections package as something you might want to look at: https://github.com/slburson/fset-java

The data structure it uses is an evolution of Stephen Adams' weight-balanced binary trees. The performance actually isn't bad, but there are newer and better choices and I'm not here to try to tell you you should use the FSet implementation.

What I would encourage you to do, though, is to have a look at the API. There may be some ideas in there you will find useful. The API was strongly influenced by a little-known proprietary language called Refine, which in turn was influenced by SETL.

In particular I would like to urge you not to name functional new-version operations the same as the corresponding mutating operation; so for instance, the operation that returns a set with a new element added should not be called add. Following SETL, I have called this operation with; plus is a reasonable choice as well. In general, I believe that functional operations should be named using nouns or prepositions, not verbs. Verbs suggest mutation. For instance, I recall reading once that users of Java's BigInteger would sometimes write x.add(y); and expect x to contain a different value afterwards; I think x.plus(y) is much more obviously an expression, not a statement.

(I suppose get on a map or list is an exception, though one could also make a case for at.)

ilya-g commented 7 years ago

In particular I would like to urge you not to name functional new-version operations the same as the corresponding mutating operation

The problem here is that we'll have to invent new names for all operations, and the resulting naming likely wouldn't look nice. Also there is no established naming for immutable collection operations, so inventing our own names could make the operations hard to explore.

Verbs suggest mutation.

There are a couple of counterexamples, such as filter, map, groupBy etc.

slburson commented 7 years ago

Okay, maybe a blanket prohibition on verbs is going too far, but I still think using the same names as existing mutating operations is going to confuse people. This is especially true in code where both mutable and functional collections are being used, for different purposes. I've worked on code like that, and it helps if the two cases are as easy to tell apart as possible, because it's easy to confuse them.

As for not "looking nice" or being "hard to explore", I don't really know what you mean. These APIs are not so wide that people can't just look through them to find what they want.

Anyway, I have several colleagues using FSet, and no one has complained to me about my naming choices.

ilya-g commented 7 years ago

In order not to enumerate all possible naming options and arguments behind them let's refer to this SO question by Jon Skeet What's the best name for a non-mutating “add” method on an immutable collection? with the variety of 74 answers. And there's related article by the same author, where he summarizes the answers while considering the name of add method for his immutable collections (spoiler: he had chosen Plus in the end).

Also we could refer to an experiment, what would happen if we name modification operations the same way as they named in mutable collections. Actually we can assume that such experiment was conducted by Microsoft, when they had released their immutable collections for .NET back in 2013, and it has been lasting for three years now.

Unfortunately, I couldn't find the reasoning behind their naming decision, and the only thing we can study now is whether it causes confusion among users or not. All that I've found is this single SO question: Immutable list not adding data. ATM this question hasn't got a lot of activity (0 votes/~600 views). We can conclude either of two things:

However the latter could be disproved with the number of downloads of Immutable Collections nuget package — it's about 2 mln times.

One option to mitigate such potential confusion is to annotate the modification operations that their return value must be used, and to provide an IDE inspection for the usages of such operations ignoring the returned value. Actually this inspection is useful to have irrespective to the chosen naming scheme.

ilya-g commented 7 years ago

Having said all that I think we'll stick with the current naming scheme for now, but we'll continue to evaluate the feedback coming from EAPing the immutable collections.

However we're open to alternative naming schemes, but the naming must satisfy the following requirements:

elizarov commented 7 years ago

I'm strongly if favor of distinct names for mutating and non-mutating operations (e.g. add is mutating, while plus is not). Kotlin lives in a mixed environment and a code that uses both mutable collections and persistent ones is to be expected. Having a distinct naming will greatly improve readability.

Miha-x64 commented 7 years ago

You can take a look at this naming example: https://github.com/Miha-x64/Blitz/blob/master/src/main/java/net/aquadc/blitz/ImmutableLongSet.java

marco-eckstein commented 2 years ago

I also think that to avoid confusion, different names should be chosen than those for mutating methods. I would prefer using the prefixes with and without. If you are still worried about discoverability, using -ing and -ed as in adding/added would be fine too, I think. plus and minus should not be used because there is the danger of a clash with the operators of the same name. At the very least, these would be confusing, which we have been trying to avoid in the first place.