What is your preferred nomenclature for two functi...
# naming
r
What is your preferred nomenclature for two functions that do the same thing, but one mutates the object, whereas the other returns a new object?
r
You could try the approach used by MutableList shuffle - in place shuffled - returns new list Although it’s not very consistently applied even within the list APIs 🙄
r
Yeah, that present vs past tense for mutable and immutable respectively seems to be the most common that I've come across, but it definitely isn't universal. It also made me wonder, if I were to adopt it, should I then go all in and have purely immutable objects always use past tense for their functions?
Anther one I've seen, though it's a bit ugly IMAO, is to have the immutable be the simple verb (e.g.
transform()
) and the mutable to append a phrase (e.g.
transformInPlace()
).
o
This is not about present vs. past tense. It is about verb "do shuffle this object" vs. participle "a (new) shuffled object".
l
I feel like verb vs participle lead the names to look too similar. If I’m skimming my code looking at why my array that I swear I sorted isn’t being sorted, it’s too easy to miss.
r
@Oliver.O Ah, that does make more sense than tense. Thanks.
l
One could imagine seeing
Copy code
val array = loadData()
array.sorted()
useArray(array)
o
It is a matter of getting used to. Consistency makes a difference. And every other option I have seen is neither consistent nor as expressive.
r
@Landry Norris That's a good point. Do you have an alternative that you prefer?
l
I like the *InPlace or some equivalent. I prefer to have something I can search for using ctrl+F
Same reason why when I write methods that have a orNull and a throwing version, I generally write a doSomethingOrNull doSomethingOrThrow pair instead of having doSomething imply throwing.
o
When looking at "shuffle" vs "shuffleInPlace" the former is ambiguous and still suggests that it could perform in the same way as the latter.
"doSomethingOrNull" and "doSomethingOrThrow" are clearly disambiguated.
l
I would agree with the ambiguity. My main point was that it’s easier to visually distinguish shuffleInplace vs shuffle than shuffled vs shuffle.
I would like to have a suffix for both, but it’s hard to think of one sometimes.
o
Sure the visual difference is, well, different. It's a tradeoff.
r
The first thing that came to mind was
toShuffled()
vs
shuffleInPlace()
, but that's just ugly.
l
shuffleNew shuffleInPlace?
o
@Ruckus
but it definitely isn't universal.
Life is too short to wait for such a thing as a universal opinion. Someone will always disagree.
r
It also has the issue that it conflicts with very common utility functions like
map
and
filter
.
Indeed, words to live by 🙂
o
It's too late for them (see the above YT issue). We can just try to do better in the future.
And one additional point: Unless there is compelling evidence to choose one option over the other, the world would be probably better off if people would just stick to the Kotlin coding conventions (more consistency = less stuff to learn on a case-by-case basis). In this case, the following applies:
The name of a method is usually a verb or a verb phrase saying what the method _does_:
close
,
readPersons
. The name should also suggest if the method is mutating the object or returning a new one. For instance
sort
is sorting a collection in place, while
sorted
is returning a sorted copy of the collection.
l
I get the argument for consistency, but some of us don’t have the best vision. sort/sorted of shuffle/shuffled is hard to see.
o
Yes, I get that. What if the IDE were to add emphasis such as
myList.*shuffle*()
vs.
myList.shuffled()
? (Assuming that object mutation is the more dangerous option.)
s
What about
shuffle()
returning a Collection/List and
shuffleItems()
returning a Unit, shuffling the items in place?
l
I could just as easily see
shuffleItems()
returning a Collection/List and
shuffle()
returning a Unit, shuffling the items in place?
o
shuffleItems
is really a more specific term of
shuffle
. It's like using synonyms for two things and then re-interpreting language to differentiate. Does not really work once you omit the explanation.
l
I think the biggest issue is the tradeoffs. I think shuffle and shuffled are really clear once you see them, but are very easy to mix up when skimming text, especially if your vision is quite poor.
o
I'd always be in favor of considering vision impairments and providing solutions for cases like this. That's why I came up with the idea of the IDE providing extra visual cues.
l
I personally use
withWhatever
or
withXxxxWhatever*ed*
when
whatever*ed*
isn't explicit enough or reads not right.
y
Since the mutating functions would most usually return Unit, this feels like a symptom of Kotlin not having a
@CheckResult
annotation, or automatically warning about unused results and having a way to signal a discardable result. Seems like it's being worked on though KT-12719
e
that's why Ruby adopted Scheme's convention:
arr.shuffle!
mutates
arr
in-place
arr.shuffle
returns a new array
probably too late to add that to Kotlin though
Java uses simple verbs on mutating operations, e.g.
.sort()
and I think it's an overall strength that Kotlin doesn't change much there
maybe
.sorted()
would have been more visually distinct from
.sort()
if had been named
.toSortedList()
, with the bonus of indicating the return type as well, which isn't obvious from the current name, but that seems too verbose for what should be the default when working with immutable data
o
While
.toSortedList()
is certainly more visually distinct, ambiguity remains: Applied to a list, it could be interpreted as "mutate that list into its sorted form".
with the bonus of indicating the return type
Heading back towards the dark ages of Hungarian Notation? 👻 For example, if the return type is a set or a list does not matter if I'm just iterating over it, so why enforce its indication? What I find particularly attractive in Kotlin is type safety without ceremony. That way, code can effectively communicate ideas without distractions by technical clutter. Regarding the best amount of visual distinction, I'd prefer not to merely speculate, but do trials and gather some hard empirical data on what really works and what doesn't.
e
we have the convention that
.toFoo()
returns a new copy in a given representation, e.g.
.toList()
,
.toSet()
, and even
.toSortedSet()
o
Yes, I'm aware. We also have
.toString()
. As long as there's a type change involved, these are somewhat OK. But they are ambiguous at least in some contexts, they have to be learned, and are not necessarily applied consistently. I'd have preferred
.asList()
. For me, the entire question is more future-oriented: What would be the best naming strategy, starting now? And then think about where it is better to stick to (weaker) conventions, because the downside of abandoning them seems to huge.
e
there is `.asList()`; it has a different meaning than
.toList()
anyhow my view is that there are alternate naming schemes but so far nothing convincingly better