puts(Array) and p(Array)

In Crystal puts(Array) behaves differently from Ruby.

Ruby

array = [1, 2, 3]

p array # => [1, 2, 3]
puts array
# => 1
# => 2
# => 3

Crystal

array = [1, 2, 3]

p array    # => [1, 2, 3]
puts array # => [1, 2, 3]

# It takes significantly more code to print each item separately
array.each { |item| puts item }

I think, Ruby’s puts is more convenient.
What’s the reason behind that divergence between Crystal and Ruby? Is that subject to change?

Crystal’s version makes a little more sense to me somehow…FWIW :)

1 Like

Why? puts and p do the same thing, it feels redundant. The only reason I can think of, is it’s consistent with puts(Tuple) and puts(Hash), but it’s unexpected (after Ruby) and useless (duplicate of p).

Without prior knowledge of Ruby’s behaviour, it seems really unexpected that it prints each item in a separate line.

1 Like

What part of Crystal users didn’t come from Ruby?

Ruby’s behavior is convenient, I sometimes use it to puts caller. Then sometimes I forget about it and find it inconvenient and I have to switch to p.

In Ruby, puts array is a special case. In Crystal we try to avoid special cases. That’s why I didn’t copy this strange behavior.

What would happen for other container types? Would they need to somehow change the behavior of puts? Why is array special? That’s why I didn’t copy it.

1 Like

@asterite I see, thank you for the explanation.

In Ruby, puts array is a special case. In Crystal we try to avoid special cases.

As far as I know, they hate it to have special cases in Ruby too, but they made one for puts(Array), for some reason.

Users who comes from Java, Go, C#, etc.

They are not the majority, but they exists.

I go to general languages Meetup to talk about Crystal.

I came from Java and C++, and I’ve actually been able to work with Ruby (specifically for Vagrant) after learning Crystal, due to the similarities.

4 Likes

I come from Javascript, Java and Python

There is no reason for that change.

Because it’s the most often used container for collecting items together to operate on them one by one afterwards.


@alex-lairan @RespiteSage @krthr

Greeting, strangers! :smile:
How do you feel about puts(Array) printing items one by one instead of emulating p(Array) as it is now? Would that be confusing for you?

I’m using Crystal from 2014 so my opinion will be biased,
but I think that p(Array) should print the array without a new line, and if you want a multi-line display, pp(Array) should give you that.

Unfortunately, it is not the case https://play.crystal-lang.org/#/r/8ogy

1 Like

I’ve come from Pascal and C (but also have some experience with Ruby) and i think puts(Array) behaving differently from puts(Tuple) would be very confusing, to a point of never using puts on something except String (so I would always do puts(x.to_s)).

1 Like

I would be unhappy with the change because it seems unnecessary and behaves differently from any other language I’ve worked with (since I have very little Ruby experience). I agree with others here that Array should behave similarly to Tuple and other Enumerable types when used with puts.

I also don’t think that it’s a bad thing that it takes more code to print array elements on multiple lines. While the array.each method you showed above is more code than just puts, it’s much more clear what’s intended. One of Crystal’s greatest strengths is that it’s naturally pretty easy to read, and I think that encouraging self-documenting code like that is more important than giving shorter ways to do everything.

To be honest, when I know I’m dealing with an array, I use puts array in Ruby if I want to print elements line by line. In Crystal I need to do puts array.join("\n") which is a bit longer.

The thing is, it took me a while to understand why Ruby was doing this strange thing with puts with Array. And from time to time it annoys me that I want to print an array like what you normally get when you puts a Hash or basically anything, and Ruby prints it line by line. Then I have to change it to p.

In Crystal you have to type a bit more for the “print each item in a line”, but I prefer consistency over special cases.

2 Likes

Clearly documenting these translations will make it easier going between Crystal <-> Ruby.

   Crystal                  Ruby
p array or puts array     p array

puts array.join("\n")     puts array
1 Like

I think this is the right way.

Strictly speaking, puts(Array) in Ruby is not the same as puts Array#join("\n") in Crystal:

ary = ["foo\n", "bar\n"]

ary.each { |i| puts i }
puts ary.join("\n")

This. Always.

1 Like

I ran into this today:
cat me.rb puts [1,2,3] ruby me.rb
1
2
3

Ruby confused me… :slight_smile: where did the brackets go? it’s like 3 separate elements now? … :)