Feature #8520

Distinct to_s methods for Array, Hash...

Added by Gernot Höflechner 11 months ago. Updated 10 months ago.

[ruby-core:55458]
Status:Feedback
Priority:Low
Assignee:Yukihiro Matsumoto
Category:-
Target version:-

Description

I apologize if something like this has already been proposed in the past, if it was, I can't find it at the moment.

Ruby 2.0 rightfully changed to behaviour of inspect (not delegating to tos anymore), as inspect was effectively disabled when you had custom tos methods implemented.

However I think that a mix of the old and the new would combine the best of both worlds.
Array or Hash tos methods should not delegate to inspect, but instead reflect the old behavior and call tos to all members of a given collection.

Use Case:
I am currently designing a fairly large application that constructs very complex objects. For debugging reasons those objects have tos methods implemented to read terminal output in a digestible format.
In constructing these to
s methods it was very convenient to string-interpolate collections of such objects.
A quick example:

class A
def initialize
@a = "Large example text"
end

def to_s
# abbreviated form
@a[0]
end
end

arr = []
5.times { arr << A.new }
arr << arr.clone

puts "#{arr}"

Ruby 1.9.3 output: [L, L, L, L, L, [L, L, L, L, L]]
Ruby 2.0.0.output: [#, #, #<A:0x00000001f52bb0 ... and much more

I deliberately nested the example - as it obstructs the use of a simple join (arr * " " => L L L L L L L L L L), which cannot reflect the array's nesting.
Printing a hash would be even more difficult - and with more nesting this becomes an immense task.

Of course someone could just adjust the to_s method, but the elegance gets lost, logging something like this would quickly lead to not so pretty code:
"The array looked like: #{arr}"

So I'd say distinct tos methods, that call tos recursively instead of delegating to inspect. Basically leaving inspect at its correct 2.0 behavior and reverting to_s (and thus #{}) back to its 1.9 behaviour.
Let's hope I am not overlooking something here.

What do you think?
Thanks for your feedback in advance,
GH

History

#1 Updated by Yukihiro Matsumoto 11 months ago

  • Status changed from Open to Feedback
  • Assignee set to Yukihiro Matsumoto
  • Priority changed from Normal to Low

Ruby 2.0 uses #tos as an alias to #inspect, so redefine #inspect instead of #tos for your class.
This might be controversial, so I don't close this issue.

Matz.

#2 Updated by Boris Stitnicky 11 months ago

According to my feelings, in your example, class A shirks its duty of defining
sensible #inspect, and the ugly ouput is a reminder of that. I feel that 2.0
behavior is more correct, in the sense that the concerns of string conversion vs.
user inspection are in fact orthogonal.

#3 Updated by Marc-Andre Lafortune 10 months ago

It could be a good idea to specialize to_s for structures.

What would be the downside of having Array#to_s call to_s on its elements while Array#inspect would call inspect? This would be the same idea as Array#eql? comparing with eql? while Array#== uses ==, even though for most classes they are aliases

#4 Updated by Gernot Höflechner 10 months ago

Thanks for the responses guys!

@matz and boris:
I deliberately left that out in my first message, when I probably shouldn't: Of course the issue can be overcome quite easily: as you said, just redefine inspect instead of to_s or alias it - that's just what I am doing in the real world.
This has imo various downsides though:

a) - We're somehow back to ruby 1.9 behaviour, as you can't call normal inspect anymore, when you - for whatever reason - wan't to see the whole output. That too can be overcome, catching the old inspect method with something else and so on... but that might be a little too much hassle for something as simple as that.
b) - It's probably semantically not ideal: Let's imagine a poll, where relatively new rubyist are asked the following question: When you call #tos on an array, what method gets called on all its elements? And what message gets sent when you call Array#inspect? I am quite confident that the result would be lopsided: tos passes to_s, inspect passes inspect. I am not even sure if you have to limit this poll to new rubyist, I guess even experienced programmers might fall for this "trap".

I am with Marc-Andre, I cannot see a downside in having two distinct approaches for Array/Hash#to_s and #inspect.

Still I can understand the point Boris made: Going back to my dumbed down example a case could be made that #inspect was the method I should have been looking for in the first place: Not a string conversion, but an inspection of an object for debugging reasons. That's almost a philosophical debate. The way I see it, #tos gives me a structured output of something in an easily digestible format - which I may like for debugging f.e. - while #inspect gives me raw and as detailed as possible information about my data.
But I think it doesn't matter where you stand here: Just let the user decide if he wants to use #to
s or #inspect - and give him just that.

Also available in: Atom PDF