[Elixir] Referenceの作り方

この記事は [Elixir その2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/elixir2) 20日目です。

前日は、「[[Elixir] Supervisor child_spec](https://qiita.com/mnishiguchi/items/f4668697cb371ea6bb39)」でした。

## はじめに

さて、今年になって[ナウでヤングでcoolな「Nerves」](https://www2.slideshare.net/takasehideki/elixiriotcoolnerves-236780506)というIoTフレームワークに出会い、今どきのカッコいい電子工作を楽しみながら、Elixirの勉強をしています。ラズパイにLEDを接続して点灯、点滅させたりするのですが、その際に使用するライブラリーがReferenceを戻り値として返してきます。
しばらくの間は、「参照」であるとの理解で問題なくコードをかけてましたが、テストコードを書いているときにReferenceを作りたくなったので、作り方を調べました。

## 結論

```elixir
iex> make_ref()
#Reference<0.1816055995.4047503364.216777>
```

## どこでReferenceに遭遇したか

LEDを接続するGPIO（汎用入出力）を操作するために使用するのが[elixir-circuits/circuits_gpio](https://github.com/elixir-circuits/circuits_gpio)です。
まず最初に行うのが、GPIOへの参照を取得することです。そこでReferenceが登場します。

```elixir
iex> {:ok, gpio_pin} = Circuits.GPIO.open(12, :output)
{:ok, #Reference<0.2184343048.2460614673.37929>}
```

そのReferenceを使用して、GPIOピンのON/OFF操作をします。

```elixir
iex> Circuits.GPIO.write(gpio_pin, 1)
:ok
```

## Circuits.GPIOソースコードを読んで見る

コードの量は思ったより少ないです。ほとんどCで書かれています。
詳しくは僕にはよく理解できませんが、Erlangの[Native Implemented Functions (NIFs)](http://erlang.org/doc/tutorial/nif.html)という機能を利用してCで書かれた関数を呼び出せるようになってます。[ここのenif_make_resource](https://github.com/mnishiguchi/circuits_gpio/blob/f6659639fe4e5478e6b2ed8525a17fd278662c95/src/gpio_nif.c#L317)関数がReferenceを取得しています。[enif_make_resource](https://erlang.org/doc/man/erl_nif.html#enif_make_resource)はオブジェクトを作るときに使用されるようです。結局よくわかりませんが、こういうものがあると分かったのでいい機会でした。

## Reference型とは

Elixirのドキュメントをよくみるとの[Built-in types](https://hexdocs.pm/elixir/Kernel.html#module-built-in-types)ひとつとして挙げられてます。

>  a unique value in the runtime system, created with `make_ref/0`

更に調べてみると、Erlangに[Reference](https://www.erlang.org/course/advanced#refs)があるので、これだと思います。

> References are erlang objects with exactly two properties:
> - They can be created by a program (using make_ref/0), and,
> - They can be compared for equality.

Erlangオブジェクトに紐付けされた[UUID](https://ja.wikipedia.org/wiki/UUID)のようなものってことですかね。

## Referenceのつくりかた

[Kernel.html#make_ref/0](https://hexdocs.pm/elixir/Kernel.html#make_ref/0)で生成可能。

```elixir
iex> make_ref()
#Reference<0.1816055995.4047503364.216777>

# 詳しくは
iex> h make_ref
```

IEx内に限り、ヘルパー関数[ref](https://hexdocs.pm/iex/IEx.Helpers.html#ref/1)を使用可能。

```elixir
iex> ref("0.1.2.3")
#Reference<0.1.2.3>

iex> ref(0, 1, 2, 3)
#Reference<0.1.2.3>

# 詳しくは
iex> h ref
```

## さいごに

因みにテストコードでやりたかったのは[こんな感じにハードウエアのモックに対してスタブ関数を定義すること](https://github.com/mnishiguchi/lcd_display/blob/c980e9a6d7766b239ec326449cf3c8e764e39375/test/lcd_display/hd44780_i2c_test.exs#L99)です。

[#NervesJP Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nervesjp)でも、[パルス幅変調 (PWM) Lチカ](https://qiita.com/mnishiguchi/items/4bdf88acf0ab0e8e2c7e)について投稿しました。Nerves楽しいですよ。

今後更に新しいことを学んだら随時内容も更新していこうと思います。

---

明日は、おなじみの@torifukukaiouさんpresents「[1260 (Elixir 1.11.2-otp-23)](https://qiita.com/torifukukaiou/items/a8f2eb1cf96e9cf385d8)」です。引き続き、Elixirを楽しみましょう。

Happy coding!

- [Elixir その1 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/elixir)
- [Elixir その2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/elixir2)
- [【毎日自動更新】QiitaのElixir LGTMランキング！](https://qiita.com/torifukukaiou/items/1edb3e961acf002478fd) by @torifukukaiou