---
title: Auto
summary: A smarter compiler
thumbnail:
author: asterite
categories: technical
tags: ["April's Fools", "macros"]
---

**Note: this was an April's Fool post. However, with Crystal macros you could do this.**

We Crystal developers believe compilers should be smart. You don't need to add type annotations everywhere:
only when needed, or when you want them. Can we make the compiler even smarter?

This past month we have been thinking that since Crystal is a relatively young language with a still
incomplete standard library and ecosystem, there are lots of things to code yet. It's unfortunate
that many of these algorithms and data structures are already present in other languages. Not only that,
but these other languages have been used for many years now, so their implementation is pretty robust and
bug free. We will have to walk the same road in Crystal. Or will we?

Well, not anymore. The next release of Crystal will have a tiny but powerful addition: an **auto** keyword.
To understand how it works, let's see it in action:

```ruby
class String
  auto def succ
  end
end

"hello".succ #=> "hellp"
```

The first thing you need to know is that `String#succ` is not in Crystal's standard library. In the code
above we define it with the **auto** keyword, leaving the body empty. We then invoke the method on some
string and it gives the correct value. Awesome! Crystal not only deduced the return type of `succ`,
it also deduced its *behaviour*!

## How **auto** is implemented

When we said **auto** is a keyword, we lied: it's a macro. Macros in Crystal receive AST nodes, that is,
they receive syntax. **auto** then receives a method definition and processes it at compile-time to generate
a method definition that implements the desired functionality:

```ruby
macro auto(method)
  ...
end
```

Macros can inspect the arguments: they can ask the method's name, arguments or where the method is defined
(String in the above example). If you need to do more complex stuff, you can invoke **run** in a macro,
like this:

```ruby
macro auto(method)
  {%- raw %}{{ run("auto/process", @type, method.name, *method.args) }}{% endraw %}
end
```

This will invoke the program `auto/process.cr` passing the type name, method name and splatted method arguments
to the program. The program then receives these arguments in the usual `ARGV` array, processes them and
outputs a method definition that will then be embedded in our original program. Neat, right? We use a similar
technique for ECR (similar to ERB): the ECR templates are processed at compile-time.

The `auto/process.cr` program does a few things: it searches the internet for relevant method definitions together
with their source code and possibly associated tests/specs. Right now this is only done for Ruby code because
of its similarity with Crystal, but support for other languages is coming soon.
Then it processes the code and generates Crystal code.

Now, this can be quite slow. In fact, it takes a few seconds (5 seconds on one of our machines). Luckily, the
generated code is cached in the usual ".crystal" directory so the next time **auto** is used for the same
method of a same type, it will reuse the cached version. But even with this penalty, think of the time
you save by using **auto**: you don't have to write the method, plus you reuse existing robust and well-tested
code!

## **auto** types

You can even use **auto** on a type:

```ruby
auto class LinkedList(T)
end

list = LinkedList(Char).new
list.push 'a'
list.push 'b'
list.push 'c'
puts list.size #=> 3
puts list        #=> ['a', 'b', 'c']
```

So the **auto** macro actually checks whether the received AST node is a class or method. For the class
case, `auto/process.cr` will search that class name on the internet and generate a definition for it
together with every method it can find for it, reusing the previous logic.

## Trying it

You can try all of this by checking out the [auto branch](https://github.com/crystal-lang/crystal/commit/46fd17de4964e648192c1f9c8a039088f6520cb0) in our GitHub repository, but you'll need
to compile a new compiler because we added some macro methods for this feature. Please understand
that this is still very new so any bug you find, please report it!
