I remember disliking the fact that Python's join method seemed to be flipped around, I never knew why they did it until you explained it here, and I can see the wisdom in that. But still, it's conceptually backwaords. You're "joining" the array (or iterator) together with a string. This means you're acting on the array/iterator, and the string is just a parameter. I don't believe Python has a way to arbitrarily attach methods to iterators, so the only way they can make join
support all iterators is to reverse it and make join
an instance method on the string, or, they could have just made join a static method on their list class (or some new iterator namespace) and added join
to that and had join
take two arguments, I would have prefered that over the reversal they did.
Anyways, to address some of your feedback
Maybe. I am thinking that joining all value together to a string makes only sense if everything is buffered already kind of. I like what you are thinking, but I feel like this is more suitable on the String prototype.
I'm not exactly sure what you mean here. If it's able to consume an arbitrary iterator, then there's going to be no guarantee that it's buffered, even in Python's case.
>>> f = open('./temp.txt', 'r')
>>> '\n===\n'.join(f) # This file object is not buffered. Python is reading the file as it joins.
'hi\n=====there\n'
The only drawback I can really see, is that it is not possible to do "1,2,3".split(",").join("-")
with the Python variant.
We won't need to worry about fluent-API support once the pipeline operator proposal gets through. You would be able to write that like this if you don't want to use the array version:
"1,2,3"
|> %.split(",")
|> %.join("-")
I think the most compelling reason to add String.prototype.join
is if there is possibilities of performance improvements under the hood.
Adding it to the iterator prototype would cause it to have the same performance optimizations. For example, I would be able to write something like this, and the engine will be able to build the joined string as it consumes the iterator, without having to build an intermediet array.
function* upTo(limit) {
for (let i = 0; i < limit; ++i) yield i
}
// join() is being called on the iterator produced by the generator.
// It's not being called on an array.
upTo(100).join(',')
Of course, if we want to go this route, we would need to request that they add this function to the collection of functions they're adding to the iterator. Who knows, maybe functions like this could end up becoming a follow-on proposal instead of part of the core.