Project

General

Profile

Actions

Feature #8520

closed

Distinct to_s methods for Array, Hash...

Added by LFDM (Gernot Höflechner) almost 11 years ago. Updated 5 months ago.

Status:
Feedback
Target version:
-
[ruby-core:55458]

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 to_s anymore), as inspect was effectively disabled when you had custom to_s methods implemented.

However I think that a mix of the old and the new would combine the best of both worlds.
Array or Hash to_s methods should not delegate to inspect, but instead reflect the old behavior and call to_s 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 to_s 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 (A 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:0x00000001f52c50 @A (A A)="Large example text">, #<A:0x00000001f52c00 @A (A A)="Large example text">, #<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 to_s methods, that call to_s 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

Updated by matz (Yukihiro Matsumoto) almost 11 years ago

  • Status changed from Open to Feedback
  • Assignee set to matz (Yukihiro Matsumoto)
  • Priority changed from Normal to 3

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

Matz.

Updated by Anonymous almost 11 years 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.

Updated by marcandre (Marc-Andre Lafortune) almost 11 years 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

Updated by LFDM (Gernot Höflechner) almost 11 years ago

Thanks for the responses guys!

@matz (Yukihiro Matsumoto) 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 #to_s 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: to_s 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, #to_s 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.

Updated by p8 (Petrik de Heus) 5 months ago

There is an open issue in Rails to limit ActiveRecord::Base#inspect for performance reasons.
https://github.com/rails/rails/issues/49707

Calling to_s on a Hash will call inspect on its contents.
ActiveRecord::Base#inspect prints all the records attributes. It loops through all attributes and filters sensitive ones.
So calling to_s on a Hash with a lot of ActiveRecord instances/attributes can result in performance issues, as it filters all attributes.

Of course this issue can be fixed in Rails by changing ActiveRecord::Base#inspect, or not calling to to_s on a large Hash.
But it might not be obvious to everyone that Hash#to_s is an alias to Hash#inspect, as a lot of objects have different behaviour for to_s and inspect.

Updated by Hanmac (Hans Mackowiak) 5 months ago

p8 (Petrik de Heus) wrote in #note-5:

There is an open issue in Rails to limit ActiveRecord::Base#inspect for performance reasons.
https://github.com/rails/rails/issues/49707

That sounds more like a Rails problem than a Ruby Problem

if the objects in an Array or Hash aren't in their already fully loaded form (with no extra DB calls required),
then its more of a problem of the library using it.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0