Skip to content

Loading…

Overridable method for string interpolation #1928

Closed
pwnall opened this Issue · 3 comments

3 participants

@pwnall
Rubinius member

This is really a Ruby language design bug, but I'd like to get some feedback from the smart folks here before going to ruby-lang.

I love programming in Ruby, and I really like being able to override everything, down to Fixnum#+. Sadly, there's currently no way to override the concatenation operation used for string interpolation.

Ideally, "I have #{3 + 2} apples" would be syntactic sugar for "I have " + (3 + 2).to_s + " apples". At the same time, I know that many templating languages rely on this particular construct being fast.

Right now, it seems that both MRI and Rubinius build the string fragments and use a special VM bytecode for concatenating the fragments. I would like to have this opcode be replaced by a call to String#join (not too hung up on the method name), which would be a native method that basically implements the stringbuild bytecode. So, in other words, String#join(*args) would be a very fast implementation of "".join(args) or "".join(*args), whichever one works better from a performance standpoint.

I realize that this adds an extra method call, and method dispatch is expensive. At the same time, most string interpolation cases have at least one to_s call. Also, for programs that don't override String#join, I'm hoping and guessing that the JIT can optimize the calls.

I would like to get your opinions on this design. A colleague of mine will be providing an implementation once we have a reasonable design.

Here's my motivation, in case you're wondering why I'm putting together this proposal. I'm trying to implement a dataflow analysis tool that adds "labels" to objects, and propagates these labels throughout a program's dataflow. For example, if a has label L1, the new object returned by a + b will also have label L1.

Also, here is a paper that ran into the same roadblock. See page 9, section "String interpolation".
http://www.cs.virginia.edu/~evans/pubs/webapps2011/guardrails-packaged.pdf

@brixen
Rubinius member

String interpolation could be essentially ary.inject("") { |ac, x| ac << x.to_s } where ary is an Array of elements from the interpolation (eg for "this #{is} a test", ary = ["this", is, "a test"]).

One problem is that since #to_s can be overridden, we have to be able to force an object into some sort of String representation.

Personally, I'm not very interested in this proposal. Any attempt to layer diagnostics or tooling on top of methods is bound to encounter "invisible" parts of the runtime. It's a beguiling invitation that Ruby allows most methods to be overridden. That facility enables writing very good and clean OO code. To have good diagnostics requires support from the runtime system. I'd rather see standard APIs developed there (eg for Debuggers, Coverage tools, GC stats, etc).

@headius

It would certainly be possible to implement, perhaps with a VM flag to enable or disable the behavior, but it's not something I'd ever do in JRuby by default.

JRuby has gone to great lengths to eliminate transient objects from string interpolation, in some cases only creating a single string for the result if the interpolated expressions are known types. Ultimately, any attempt to make interpolation call String methods would add more transient objects and more dynamic calls to what's currently a pretty fast implementation.

@brixen
Rubinius member

There's nothing actionable on this ticket. Please address the issue with MRI on ruby-core mailing list or their issue tracker.

@brixen brixen closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.