Why I love Ruby: almost everything is a call
Tags: ruby, crystal
Published: 2022-02-19 09:57:46

---
title: Why I love Ruby: almost everything is a call
published: true
description: 
tags: ruby, crystal
// cover_image: 
series: Why I love Ruby
---

Right on the [main page of the Ruby language](https://www.ruby-lang.org/en/about/) there's this beautiful quote from Matz:

> Ruby is simple in appearance, but is very complex inside, just like our human body.

It's Ruby's simplicity that I really like.

If you ask me "What do you see when you see Ruby code?" my answer is **method calls**. 

![](https://user-images.githubusercontent.com/209371/154746251-d1beb1a6-29a0-43cd-9b8f-9bb72cd380f8.png)

Take a look at this code:

```ruby
require "set"

class MySet
  include Enumerable

  attr_reader :inner_set

  # ...
end
```

There are some things here:
- we `require` some external code
- we declare a class with the `class` keyword
- we include functionality from another module with `include`
- we declare a read-only property with `attr_reader`

It turns out, only `class` is special here: it's a language construct that lets you define classes. But [require](https://ruby-doc.org/core-3.1.0/Kernel.html#method-i-require) is a method call defined by Ruby, and the same is true about [include](https://ruby-doc.org/core-3.1.0/Module.html#method-i-include) and [attr_reader](https://ruby-doc.org/core-3.1.0/Module.html#method-i-attr_reader). They **look** like keywords, like something special, but they are just regular methods.

This ability of having almost everything look the same, in a consistent way, is what lets you, the Ruby user, also define things that look like language keywords, but are just ordinary methods.

In fact, it's very easy to define `attr_reader` ourselves. Because `attr_reader` already exists, lets use the name `getter` for that:

```ruby
class Module
  def getter(name)
    symbol = "@#{name}".to_sym
    define_method(name) do
      instance_variable_get(symbol)
    end
  end
end

class Point
  getter :x
  getter :y

  def initialize(x, y)
    @x = x
    @y = y
  end
end

point = Point.new 1, 2
point.x # => 1
point.y # => 2
```

And there we have it!

Well, using `getter` is simple. Maybe defining it is a bit more complex... but it's definitely possible!

Maybe the additional feature of not having to put parentheses around method calls makes this look more like a keyword than a method. Imagine if parentheses were required for method calls:

```ruby
require("set")

class MySet
  include(Enumerable)

  attr_reader(:inner_set)

  # ...
end
```

They don't look like keywords anymore, right? My guess is that allowing to omit parentheses was done for exactly this reason, but of course you can omit parentheses anywhere because Ruby doesn't know if you are going to use something "like a keyword" or not.

This of course is used in Ruby **a lot**. Here's an example of Rails' ActiveRecord:

```ruby
class User < ApplicationRecord
  has_many :posts
end
```

To be honest, a snippet like that might have been one of the first code snippets I stumbled upon when I was learning Ruby together with Ruby on Rails. With this, you can kind of create your own mini-language for users. And all these languages will be relatively easy to use: they will all be based around method calls. Of course the names will vary, or the number of arguments. But in the end they are all method calls.

One other language that did this, and it actually did it better, or more consistently, is Elixir. In Elixir you define a module like this:

```elixir
defmodule SomeModule do
  # ...
end
```

You define a function like this:

```elixir
def method do
end
```

You use an if like this:

```elixir
if something do
end
```

Note that there's always a `do` in the end. These are all functions defined by Elixir! (well, technically they are macros) For example, here are the docs of [defmodule](https://hexdocs.pm/elixir/1.13/Kernel.html#defmodule/2), from which you can jump to the source code. This is brilliant!

Like in Ruby, this also means that in Elixir you will be using the same small language (calls) for almost everything.

In other languages you might be able to do the same thing, but there might be other syntax involved. For example in Rust you call macros with a bang at the end:

```rust
format!("Hello, {}!", "world");
```

In Julia you use `@` to call macros:

```julia
macro sayhello()
  return :( println("Hello, world!") )
end

@sayhello()
```

In D you can use the [mixin](https://dlang.org/articles/mixin.html) keyword to generate code at compile-time:

```dlang
template GenStruct(string Name, string M1)
{
    const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}

mixin(GenStruct!("Foo", "bar"));
```

This might seem like a little thing, but from a user perspective you have to know what you are using. "Oh, I'm using a macro so I have to do it this way." In Ruby and Elixir it's just "I call it."

Carole King [couldn't have said it better](https://youtu.be/eAR_Ff5A8Rk?t=80):

> Winter, spring, summer or fall
> All you have to do is call

Because with Ruby... you've got a friend 😌

For Crystal we considered having a different syntax for invoking macros, but in the end we used the same syntax as for method calls. And we really like the end result! Take a look at this Crystal code:

```crystal
record Point, x : Int32, y : Int32

point = Point.new(1, 2)
```

It looks like `record` is a keyword that defines a type with two properties. But it's actually a macro, [here](https://crystal-lang.org/api/1.3.2/toplevel.html#record%28name%2C%2Aproperties%29-macro)'s the documentation.

As a comparison, Java 14 added records to the language (where did they get that name from?! 😮) by introducing a new keyword:

```java
record Rectangle(float length, float width) { }
```

If Java had a way to reduce such boilerplate right in the language itself, it wouldn't need to introduce keywords: they could just do it with the language itself. As a bonus things would get automatically documented in the API docs.

One other benefit of having such constructs be methods or macros in a language is that, at least in Ruby and Crystal, a user can redefine them. For example [zeitwerk redefines require](https://github.com/fxn/zeitwerk/blob/960dbdc25024a801de0c38a2928c12a450c967da/lib/zeitwerk/kernel.rb#L24) and makes it work in a different, better way. In what other language can you do this?

# Coming up next...

In the next blog post I'll be talking about being able to design that perfect API.