3

Sometimes I need such method, which could change class of its own object. There are String#delete!, #downcase!, #encode!, #gsub!, #strip!, #slice!, etc. They are all trying to change string, but resulting class is anyway still String. And I want a method, which can convert String to Array. Some way to make this:

irb(main):082:0> str = "qwerty"
=> "qwerty"
irb(main):083:0> str.split! "e"
=> ["qw", "rty"]
irb(main):084:0> str
=> ["qw", "rty"]

Is it possible? Maybe some cool japan kung-fu or ugly bicycles — I would like to see any solution.

AstroCB
  • 12,337
  • 20
  • 57
  • 73
Nakilon
  • 34,866
  • 14
  • 107
  • 142

3 Answers3

11

Nope, not possible. Objects can't change their classes in Ruby.

In Smalltalk, for example, you could use become::

becomeSubStrings: aString
    self become: (self subStrings: aString).

If you call it like this:

s := 'qwerty'.
s becomeSubStrings: 'e'.

Now, s is an array:

Transcript show: s printString.

The result is:

#('qw' 'rty')

Technically, become: doesn't change the class of the object, rather it lets one object become another object. In this case, we let self become the result of self subStrings:, which splits the string into an array of substrings. The result is the same: the original string receiver is now an array.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • "I don't know, how to solve it" is not a garantee of impossibility, until it does not have more official proofs. – Nakilon Sep 25 '10 at 06:05
  • Nakilon: Since there is no official language specification for Ruby, you take the Ruby MRI as reference implementation. And the Ruby MRI doesn't support changing the class of an object. – joschi Sep 25 '10 at 07:12
  • @joschi: While Ruby is not specified in the way e.g. Common Lisp is, the various new implementations at least lead to RubySpec: http://www.rubyspec.org/ – Michael Kohl Sep 25 '10 at 08:03
  • Are there any languages where objects can change their class? – Andrew Grimm Sep 25 '10 at 11:54
  • @Andrew Grimm: In Smalltalk, you could do it using `become:`. – Jörg W Mittag Sep 25 '10 at 14:18
  • @Andrew Grimm: And in Javascript, you can set an object's prototype, which is roughly equivalent (since it uses prototype-based inheritance rather than class-based inheritance). – Chuck Sep 29 '10 at 06:35
  • @Chuck: I'm pretty sure that setting the prototype property is not possible in ECMAScript/JavaScript. It *is* possible in ScriptMonkey/SpiderMonkey/TraceMonkey/JägerMonkey (i.e. in Firefox) and maybe also in Rhino, but that is a non-standard, interpreter-specific extension. – Jörg W Mittag Sep 29 '10 at 13:07
  • 8 years have passed, wow. Wondering about JS, did this ability become standard? – Nakilon Oct 31 '18 at 08:08
0

Jörg W Mittag's answer is solid. It is a fundamental attribute of Ruby as a language that you can't change an object's class.

The best you can do is re-assign the variable as I am sure you are already doing:

irb(main):082:0> str = "qwerty"
=> "qwerty"
irb(main):083:0> str = str.split "e"
=> ["qw", "rty"]
irb(main):084:0> str
=> ["qw", "rty"]
Bo Jeanes
  • 6,294
  • 4
  • 42
  • 39
0

This is only possible using evil-ruby (at least I'm pretty sure evil-ruby supports this). It is a really clever hack that coaxes Ruby into doing things it was never meant to do, but also an unportable hack that has been known to cause actual segfaults in Ruby code using it. You should absolutely not use it in production code.

Otherwise, give your string an internal array and make it delegate all messages to the array (along the lines of BlankSlate + Forwardable).

It's still not something I would want to do. I can't imagine a situation where such a minor convenience outweighs the hackness of the implementation.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • This is similar to the Firefox thing: evil-ruby is a MRI extension. I.e.: it is *not* Ruby, it's C. And it works only on MRI, not on YARV, JRuby, IronRuby, Rubinius, MacRuby, SmallRuby, MagLev, Cardinal, tinyrb, RubyGoLightly, BlueRuby, HotRuby, Ruby Red, Red Sun, Ruby.NET, XRuby or any other Ruby implementation. Basically, what you are saying is: "if you patch the interpreter, so that the language it interprets is no longer Ruby, then you can do it." – Jörg W Mittag Sep 29 '10 at 13:12
  • And you are right about the stability: evil-ruby works by modifying private, internal, undocumented, unstable implementation details of MRI. Since those are not part of the public API, and often not even part of any API *at all* (public or private) but simply incidental implementation details, they can change in incompatible ways even in minor releases (and even patch releases) or through minor patches (e.g. Ruby Enterprise Edition), which if you're lucky will result in the interpreter in spectacular ways and if not, it will simply result in program unpredictably giving the wrong answers. – Jörg W Mittag Sep 29 '10 at 13:16