8.4 Rings

# Rings

An interesting spin on standard lists are rings. If you know some programming, you might have come across ring buffers or ring arrays. Here, we'll just go for ring - it's short and simple.

In the previous section on lists we saw how we could fetch elements out of them by using the indexing mechanism:

```
puts [52, 55, 59][1]
```

Now, what happens if you want index `100`? Well, there's clearly no element at index 100 as the list has only three elements in it. So Sonic Pi will return you `nil` which means nothing.

However, consider you have a counter such as the current beat which continually increases. Let's create our counter and our list:

```
counter = 0
notes = [52, 55, 59]
```

We can now use our counter to access a note in our list:

```
puts notes[counter]
```

Great, we got `52`. Now, let's increment our counter and get another note:

```
counter = (inc counter)
puts notes[counter]
```

Super, we now get `55` and if we do it again we get `59`. However, if we do it again, we'll run out of numbers in our list and get `nil`. What if we wanted to just loop back round and start at the beginning of the list again? This is what rings are for.

## Creating Rings

We can create rings one of two ways. Either we use the `ring` function with the elements of the ring as parameters:

```
(ring 52, 55, 59)
```

Or we can take a normal list and convert it to a ring by sending it the `.ring` message:

```
[52, 55, 59].ring
```

## Indexing Rings

Once we have a ring, you can use it in exactly the same way you would use a normal list with the exception that you can use indexes that are negative or larger than the size of the ring and they'll wrap round to always point at one of the ring's elements:

```
(ring 52, 55, 59)[0] #=> 52
(ring 52, 55, 59)[1] #=> 55
(ring 52, 55, 59)[2] #=> 59
(ring 52, 55, 59)[3] #=> 52
(ring 52, 55, 59)[-1] #=> 59
```

## Using Rings

Let's say we're using a variable to represent the current beat number. We can use this as an index into our ring to fetch notes to play, or release times or anything useful we've stored in our ring regardless of the beat number we're currently on.

## Scales and Chords are Rings

A useful thing to know is that the lists returned by `scale` and `chord` are also rings and allow you to access them with arbitrary indexes.

## Ring Constructors

In addition to `ring` there are a number of other functions which will construct a ring for us.

* `range` invites you specify a starting point, end point and step size.
* `bools` allows you to use `1`s and `0`s to succinctly represent booleans.
* `knit` allows you to knit a sequence of repeated values.
* `spread` creates a ring of bools with a Euclidean distribution.

Take a look at their respective documentation for more information.

