From: "Dan0042 (Daniel DeLorme) via ruby-core" Date: 2025-07-09T18:41:02+00:00 Subject: [ruby-core:122699] [Ruby Feature#21386] Introduce `Enumerable#join_map` Issue #21386 has been updated by Dan0042 (Daniel DeLorme). I am against this. ergonomics: Adding a special "X_Y" method for every common pattern of "X followed by Y" is truly horrible for the ergonomics of the language. It only multiplies the number of useless details the programmer should remember, without adding any expressiveness. Just because "map + join" is a common pattern doesn't mean it benefits from being expressed as a single method. performance: This appears intended to improve performance, but is there any benchmark? Is this really a measurable cost in any program, anywhere? It seems to me like a good JIT with escape analysis might already handle this for you, without having to remember the "special method for performance". Sorry but it looks entirely like premature micro-optimization to me. ---------------------------------------- Feature #21386: Introduce `Enumerable#join_map` https://bugs.ruby-lang.org/issues/21386#change-113976 * Author: matheusrich (Matheus Richard) * Status: Open ---------------------------------------- ### Problem The pattern `.map { ... }.join(sep)` is extremely common in Ruby codebases: ```ruby users.map(&:name).join(", ") ``` It���s expressive but repetitive (both logically and computationally). This pattern allocates an intermediate array and does two passes over the collection. Real-world usage is widespread: - [Open source Ruby projects using this pattern](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F&type=code) - [Within Rails](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F+org%3Arails&type=code) - [Within Ruby itself](https://github.com/search?q=lang%3Aruby+%2F%5C.map%5Cs*%5C%7B%5B%5E%7D%5D*%5C%7D%5C.join%2F+org%3Aruby&type=code) ### Proposal Just like `filter_map` exists to collapse a common `map + compact`, this proposal introduces `Enumerable#join_map`, which maps and joins in a single pass. ```ruby users.join_map(", ", &:name) ``` A Ruby implementation could look like this: ```ruby module Enumerable def join_map(sep = "") return "" unless block_given? str = +"" first = true each do |item| str << sep unless first str << yield(item).to_s first = false end str end end ``` The name `join_map` follows the precedent of `filter_map`, emphasizing the final operation (`join`) over the intermediate (`map`). ### Prior Art Some other languages have similar functionality, but with different names or implementations: #### Elixir Elixir has this via [the `Enum.map_join/3` function](https://hexdocs.pm/elixir/1.12/Enum.html#map_join/3): ```elixir Enum.map_join([1, 2, 3], &(&1 * 2)) "246" Enum.map_join([1, 2, 3], " = ", &(&1 * 2)) "2 = 4 = 6" ``` #### Crystal Crystal, on the other hand, [uses `Enumerable#join` with a block](https://crystal-lang.org/api/1.16.3/Enumerable.html#join%28separator%3D%22%22%2C%26%3AT-%3E%29-instance-method): ```crystal [1, 2, 3].join(", ") { |i| -i } # => "-1, -2, -3" ``` #### Kotlin Kotlin has a similar [function called `joinToString`](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html) that can take a transformation function: ```kotlin val chars = charArrayOf('a', 'b', 'c') println(chars.joinToString() { it.uppercaseChar().toString() }) // A, B, C ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/