Project

General

Profile

Actions

Feature #19302

closed

Non-destructive String#insert

Added by noraj (Alexandre ZANNI) almost 2 years ago. Updated almost 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:111585]

Description

It would be nice to have a non-destructive version of String#insert to be able to work with frozen literals.

Current behavior

There is only a destructive version of String#insert that will throw an error if the string is frozen.

irb(main):007:0> a = 'foobar'.freeze
irb(main):008:0> b = a.insert(3,'baz')
(irb):8:in `insert': can't modify frozen String: "foobar" (FrozenError)
        from (irb):8:in `<main>'                                  
        from /home/noraj/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/irb-1.6.2/exe/irb:11:in `<top (required)>'
        from /home/noraj/.asdf/installs/ruby/3.2.0/bin/irb:25:in `load'
        from /home/noraj/.asdf/installs/ruby/3.2.0/bin/irb:25:in `<main>'

This can happen pretty quickly when you have # frozen_string_literal: true in all your files.

Idea of implementation

def insert_nd(idx, str2)
  self[0...idx] + str2 + self[idx..]
end

Note: this is a draft, as it doesn't handle negative index in the same way as insert

Idea of naming

Ideally the actual String#insert would have been String#insert! so that the non-destructive version could be String#insert, but naturally that won't do as a renaming will cause a breaking change.

A more viable option would be to name it insert_nd (nd for non-destructive) but it's may not be following a naming convention.

Another idea to avoid confusion would be to avoid using insert and rather use a synonym like place, slip, slot, lodge, etc.

Actions #1

Updated by noraj (Alexandre ZANNI) almost 2 years ago

  • Tracker changed from Bug to Feature
  • ruby -v deleted (ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux])
  • Backport deleted (2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN)

Updated by austin (Austin Ziegler) almost 2 years ago

Ruby strings are mostly copy-on-write, so string.dup.insert(3, 'baz') would solve the issue, and it could be written (I believe) as -string.insert(3, 'baz') in modern Ruby.

Updated by jeremyevans0 (Jeremy Evans) almost 2 years ago

austin (Austin Ziegler) wrote in #note-2:

Ruby strings are mostly copy-on-write, so string.dup.insert(3, 'baz') would solve the issue, and it could be written (I believe) as -string.insert(3, 'baz') in modern Ruby.

-string.insert(3, 'baz') is parsed as -(string.insert(3, 'baz')), which is not the order of operations desired, since it is definitely destructive. Also, you don't want -, as that is dedup ((-string).insert(3, 'baz') results in a FrozenError). Maybe you were thinking of +string instead of -string, but if string is mutable, that doesn't make a copy, so it becomes a destructive operation. The initial suggestion of string.dup.insert(3, 'baz') makes the most sense.

In terms of the feature request, I'm against adding such a method. The need for it seems uncommon, and it is easy to use dup to handle it when it is needed.

Updated by noraj (Alexandre ZANNI) almost 2 years ago

jeremyevans0 (Jeremy Evans) wrote in #note-3:

austin (Austin Ziegler) wrote in #note-2:

In terms of the feature request, I'm against adding such a method. The need for it seems uncommon, and it is easy to use dup to handle it when it is needed.

You made a point. Creating non-destructive variant of any destructive method seems unnecessary since there is dup that is pretty easy to use and universal.

Updated by noraj (Alexandre ZANNI) almost 2 years ago

I think we can close this issue.

Actions #6

Updated by jeremyevans0 (Jeremy Evans) almost 2 years ago

  • Status changed from Open to Closed
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0