40357
Elixirでモジュール外に公開する定数を定義する方法はあるのでしょうか？

モジュール内で使う場合はアットリビュートを使うのが一般的なようです。  
[http://elixir-ja.sena-net.works/getting_started/14.html#14.2-定数として---as-
constants](http://elixir-ja.sena-
net.works/getting_started/14.html#14.2-%E5%AE%9A%E6%95%B0%E3%81%A8%E3%81%97%E3%81%A6
---as-constants)

一方で、モジュール外に公開する定数を定義したい場合はどのような方法を取るのが一般的でしょうか？  
まず、下記コードの1のようなアットリビュートはモジュール外からは参照できません。  
2のように関数を定数のように扱えば可能ですが、できれば3のような形式で定数は定数として扱えればと思っています。

```

    defmodule Sample do
        # 1. アットリビュート(モジュール内でのみ参照可能)
        @private_const_value 1
        # 2. 関数を定数のように扱う(これは可能)
        def const_value_func, do: 3
        # 3. 定義イメージ(コンパイルエラー)
        PUBLIC_CONST_VALUE = 2
    end
    
    defmodule Client do
        def foo() do
            # 1. アットリビュートは他モジュールでは参照不可
            IO.puts "CONST = #{Sample.@private_const_value}"
            # 2. 関数を定数として使う
            IO.puts "CONST = #{Sample.const_value_func}"
            # 3. 他モジュールで定義した定数を参照
            IO.puts "CONST = #{Sample.PUBLIC_CONST_VALUE}"
        end
    end
    
```

英語版にマルチポストしました。  
<https://stackoverflow.com/questions/47861754/how-to-define-shared-constant-
on-elixir>
CC BY-SA 3.0
2017-12-18T02:54:36.033
40349
2017-12-19T05:40:36.620
2017-12-18T03:26:30.410
23348
23348
question
elixir
Elixirでモジュール外に公開する定数を定義する方法
[英語版の方で回答](https://stackoverflow.com/questions/47861754/how-to-define-shared-
constant-on-elixir)を貰えたので、それをベースに自己回答します。

モジュールで定数を区切りたいという要求が無いならば、`config/xxx.exs`に記載し、`System.get_env/1`や`Application.get_env/2`でアクセスすれば良い。

モジュールで区切りたい場合は2通りの方法がある。

### 関数を使う方法

本質的には質問で書いたものと同じだが、ユーティリティマクロを定義することで、明白に定数であるという書き方にすることもできる。

```

    defmodule Constant do
      defmacro const(name, value) do
        quote do
          def unquote(name), do: unquote(val)
        end
      end
    end
    
    defmodule Sample do
      require Constant
      import Constant
      const const_value, 1
    end
    
    defmodule Client do
      def foo, do: Sample.const_value
    end
    
```

確かとは言えないが、arityが0で副作用のない関数はコンパイル時に最適化され、コンパイル時評価となるかもしれない。

### マクロを使う方法

単にマクロを使うこともできる。  
マクロはコンパイル時に評価されることが確約されるが、requireしなければならないという煩わしさがある。

```

    defmodule Sample do
      defmacro const_value, do: 1
    end
    
    defmodule Client do
      require Sample
      def foo, do: Sample.const_value
    end
    
```
CC BY-SA 3.0
2017-12-18T06:51:47.020
40357
2017-12-19T05:40:36.620
2017-12-19T05:40:36.620
23348
23348
40349
answer