From`# =>` to `#p`
Tags: crystal, todayilearned, ruby
Published: 2022-04-25 13:05:09

Sometimes writing documentation can lead us to discover some details of a language!

I opened a PR adding documentation about [Generics](https://crystal-lang.org/reference/1.4/syntax_and_semantics/generics.html) _with a variable number of type arguments_ in [Crystal](https://crystal-lang.org/) with some code examples using `# =>`.

Here's a simplified example:

```crystal
puts typeof("Hello!") # => String
```

But then I got a suggestion that read (broadly speaking): use `# =>` next to an expression to show what the result of that said expression would be. 

In other words: If we have the expression `40 + 2` then we can add a comment using `# =>` showing the expected result:

```crystal
40 + 2 # => 42
```

Let's see if that is the expected result using [`#p`](https://crystal-lang.org/api/1.4.0/toplevel.html#p%28object%29-class-method):

```crystal
p 40 + 2
```

the output would read:

```terminal
42
```

## So, what was the problem with the first example?

```crystal
puts typeof("Hello!") # => String
``` 

The suggestion continued: [...] `#puts` returns `nil`.

😲 So if `#puts` returns `nil` and `# =>` _shows_ the result of evaluating the expression, then the correct comment would be:

```crystal
puts typeof("Hello!") # => nil
```

Well ... this is not what we want! 🥲

## Documenting with `# =>`

The last part of the suggestion read: [...] Also, `#p` uses `#inspect` and returns its argument.

So, maybe we can write:

```crystal
p typeof("Hello!") # => String
```

Technically speaking this is correct because `#p` not only prints `String` which is the value of `typeof("Hello!")` but also **returns** that said value.

It's correct but ... we don't need to use `#p`. We only need `# =>` for showing the expected value, like this:

```crystal
typeof("Hello!") # => String
```

And now the code is well documented! 🤓🎉

### Another example 

Just to reinforce what we've just learned, let's see another example. This one is taken right from the [documentation](https://crystal-lang.org/reference/1.4/syntax_and_semantics/literals/string.html#interpolation):

```crystal
a = 1
b = 2
"sum: #{a} + #{b} = #{a + b}" # => "sum: 1 + 2 = 3"
```

In this example we are defining a string literal using interpolation (which let us embed expressions) and so with the use of `# =>` we are showing the resulting string.

---

Up to this point, we have learned how to document lines of code using comments with `# =>`. Great! 

And all this led us to see the difference between `#p` and `#puts` ... so maybe we can take a look at the implementation of these two methods? 🤔 ... yeah! Let's do that! 🤓🎉

But before doing that ...

> 📚 **Did you know?**
> Methods `#puts` and `#p` also exist in Ruby.
> They are implemented in module `Kernel` and with the same behaviour.
> We can read the implementations for [`#puts`](https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-puts) and [`#p`](https://ruby-doc.org/core-3.1.2/Kernel.html#method-i-p) written in C in the documentation itself.

And now ... 🥁 

## `#puts` vs `#p` under the hood 🔬

### `#puts`

Here is [the source code](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/kernel.cr#L385) for `#puts`:

```crystal
def puts(*objects) : Nil
  STDOUT.puts *objects
end
```

As we can see it forwards the responsibility to `IO#puts`. Let's see [the implementation](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/io.cr#L216):

```crystal
def puts(string : String) : Nil
  self << string
  puts unless string.ends_with?('\n')
  nil
end
```

Great! The method writes the string and it returns `nil` (as we were already expecting).

### `#p`

Now let's see [the implementation](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/kernel.cr#L393) of `#p`:

```crystal
def p(object)
  object.inspect(STDOUT)
  puts
  object
end
```

First, we may notice that the method returns (again, as we were expecting) the argument.

Then we may notice it forwards the "print responsibility" to `Object#inspect(io : IO)`. Here is [the source code](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/object.cr#L155):

```crystal
def inspect(io : IO) : Nil
  to_s io
end
```

Let's follow the code path and continue with [the implementation](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/object.cr#L105) of `Object#to_s(io : IO)`:

```crystal
abstract def to_s(io : IO) : Nil
```

Ok, we've just found an `abstract` method. 

Because we are trying to "print" a `Class` (remember `p typeof("Hello!") # => String`), let's see how `Class#to_s(io : IO)` is [implemented](https://github.com/crystal-lang/crystal/blob/ef05e26d6/src/class.cr#L148):

```crystal
def to_s(io : IO) : Nil
  io << {{ @type.name.stringify }}
end
```

We can see `Class#to_s` outputs the `Class` string representation. 

And we may read about the use of `{{ }}` in the [macros docs](https://crystal-lang.org/reference/1.4/syntax_and_semantics/macros/index.html) 🤓

> 🤯 **Did you notice?**
> We've just learned how the methods `#puts` and `#p` are implemented, and all the time we were reading code in Crystal.
> Yes! Crystal's `stdlib` is written in Crystal itself, making it a lot more natural to inspect and learn how the language works under the hood. 🤩

### Example

Here is another example that shows the difference between using `#puts` and `#p`:

```crystal
class A
  def initialize
    @foo = "Foo"
    @bar = "Bar"
  end
end
 
a = A.new
puts a
p a
```

The output will read:

```terminal
#<A:0x7f25e8f28ea0>
#<A:0x7f25e8f28ea0 @foo="Foo", @bar="Bar">
```

We can see that `#p` (which we now know uses `#inspect`) prints more information.

## Farewell and see you later

Let's recap:
* We have learned about documenting lines of code using `# =>`.
* We have traveled through the implementation of `#puts` and `#p`.
* And finally we have seen an example with the difference between using `#puts` and `#p`.

Hope you enjoyed it! 😃