13 alias,require와 import - alias, require and import

소프트웨어 재사용을 용이하게하기 위해 Elixir는 3개의 지시어(directives)를 제공합니다. 밑에서 살펴보겠지만 lexical scope를 가지고 있어 지시어(directives)라고 합니다.

In order to facilitate software reuse, Elixir provides three directives. As we are going to see below, they are called directives because they have lexical scope.

13.1 alias - alias

alias로 어떤 모듈에도 별명을 붙일 수 있습니다. Math모듈이 수학에 특화된 오퍼레이션을 위해 특별한 리스트의 구현을 사용한다고 가정해봅시다:

alias allows you to set up aliases for any given module name. Imagine our Math module uses a special list implementation for doing math specific operations:

defmodule Math do
  alias Math.List, as: List
end

이제부터 List의 모든 참조는 Math.List로 확장됩니다. 오리지날 List에 접근하려면 Elixir 모듈을 통해 접근하게 됩니다:

From now on, any reference to List will automatically expand to Math.List. In case one wants to access the original List, it can be done by accessing the module via Elixir:

List.flatten             #=> uses Math.List.flatten
Elixir.List.flatten      #=> uses List.flatten
Elixir.Math.List.flatten #=> uses Math.List.flatten

주의: Elixir에 정의된 모든 모듈은 Elixir 네임스페이스에 정의되어 있습니다. 그러나 편의를 위해 참조 할 때 "Elixir"를 생략 할 수 있습니다.

Note: All modules defined in Elixir are defined inside a main Elixir namespace. However, for convenience, you can omit "Elixir." when referencing them.

Alias는 숏컷(shortcuts)을 정의하는데 자주 사용됩니다. 사실 :as옵션 없이 alias를 호출하면 모듈 이름의 마지막 부분을 자동으로 별칭(alias)으로 설정합니다. 예를들면:

Aliases are frequently used to define shortcuts. In fact, calling alias without an :as option sets the alias automatically to the last part of the module name, for example:

alias Math.List

다음과 같습니다:

Is the same as:

alias Math.List, as: List

aliaslexical scope 하기 때문에 특정 함수안에서도 별칭(alias)을 설정 할 수 있습니다:

Note that alias is lexically scoped, which allows you to set aliases inside specific functions:

defmodule Math do
  def plus(a, b) do
    alias Math.List
    # ...
  end

  def minus(a, b) do
    # ...
  end
end

위의 예와 같이 alias를 함수 plus/2에서 호출해도, 별칭(alias)은 함수 plus/2내에서만 유효하며 minus/2에 전혀 영향을주지 않습니다.

In the example above, since we are invoking alias inside the function plus/2, the alias will just be valid inside the function plus/2. minus/2 won't be affected at all.

13.2 require - require

Elixir는 메타 프로그래밍(코드를 생성하는 코드를 작성)을위한 메커니즘으로 매크로를 제공합니다.

Elixir provides macros as a mechanism for meta-programming (writing code that generates code).

매크로는 실행 및 컴파일시에 확장되는 코드의 덩어리입니다. 이 말은 매크로를 사용하기 위해서는 모듈의 구현이 컴파일 중에 있어야 한다는 의미입니다. require 지시어(directives)를 사용하면 매크로를 컴파일하고 이후에 사용할 수 있습니다:

Macros are chunks of code that are executed and expanded at compilation time. This means, in order to use a macro, we need to guarantee its module and implementation are available during compilation. This is done with the require directive:

iex> Integer.is_odd(3)
** (CompileError) iex:1: you must require Integer before invoking the macro Integer.is_odd/1
iex> require Integer
nil
iex> Integer.is_odd(3)
true

Elixir에서 Integer.is_odd?/1는 매크로로 정의되어 있기 때문에 가드(guard)로 사용할 수 있습니다. 즉, Integer.is_odd?/1을 실행하기 위해서는 먼저 Integer 모듈이 필요합니다.

In Elixir, Integer.is_odd/1 is defined as a macro so it can be used as guards. This means that, in order to invoke Integer.is_odd/1, we need to first require the Integer module.

일반적으로 모듈의 매크로를 사용하는 경우를 제외하고는 사용하기 전에 모듈을 require할 필요가 없습니다. 로드되지 않은 매크로를 호출하려고 하면 오류가 발생합니다. alias 지시어(directives)와 마찬가지로 require도 lexically scoped인 것에 주목하십시오. 매크로에 대해서는 이후의 장에서 다시 자세히 이야기 할것입니다.

In general a module does not need to be required before usage, except if we want to use the macros available in that module. An attempt to call a macro that was not loaded will raise an error. Note that like the alias directive, require is also lexically scoped. We will talk more about macros in a later chapter.

13.3 import - import

규정된 이름을 사용하지 않고 다른 모듈의 함수 또는 매크로에 쉽게 접근하고 싶을 때 import를 사용합니다. 예를들어 Listduplicate함수를 여러 번 사용하려면 그냥 import 하면 됩니다:

We use import whenever we want to easily access functions or macros from other modules without using the qualified name. For instance, if we want to use the duplicate function from List several times, we can simply import it:

iex> import List, only: [duplicate: 2]
nil
iex> duplicate :ok, 3
[:ok, :ok, :ok]

이 경우, List에서 duplicate(인자가 2개인것)함수만 가져올 수 있습니다. 비록 :only는 옵션이지만 사용을 권장하고 있습니다. :except도 옵션으로 제공됩니다.

In this case, we are importing only the function duplicate (with arity 2) from List. Although :only is optional, its usage is recommended. :except could also be given as an option.

import:only옵션으로 :macros:functions을 전달할 수도 있습니다. 예를들어 모든 매크로를 가져 오려면 이렇게 쓸 수 있습니다:

import also supports :macros and :functions to be given to :only. For example, to import all macros, one could write:

import Integer, only: :macros

또는 모든 함수를 가져오려면 이렇게 쓸 수 있습니다:

Or to import all functions, you could write:

import Integer, only: :functions

import 또한 lexically scoped인 점에 유의하십시오, 이 말은 특정 함수에서 특정 매크로를 가져올 수 있다는 것을 의미합니다:

Note that import is also lexically scoped, this means we can import specific macros inside specific functions:

defmodule Math do
  def some_function do
    import List, only: [duplicate: 2]
    # call duplicate
  end
end

위의 예에서 List.duplicate/2는 특정 함수 내에서만 보입니다. duplicate/2는 모듈의 다른 어떤 함수에서도 (물론 다른 모듈에서도)사용할 수 없습니다.

In the example above, the imported List.duplicate/2 is only visible within that specific function. duplicate/2 won't be available in any other function in that module (or any other module for that matter).

모듈을 import하면 자동으로 require한다는 점에 유의하십시오.

Note that importing a module automatically requires it.

13.4 Alias - Aliases

이 시점즈음에는 도대체 Elixir의 별칭(alias)은 실제로 무엇이며 어떻게 표현되고 있는지 궁금해하고 있을것입니다.

At this point, you may be wondering, what exactly an Elixir alias is and how it is represented?

Elixir의 별칭(alias)은 (String, Keyword등과 같은) 컴파일하는 동안 원자형으로 변환되는 대문자로 시작하는(capitalized) 식별자입니다. 예를들어 String별칭(alias)은 기본적으로 원자형 :"Elixir.String"로 변환됩니다:

An alias in Elixir is a capitalized identifier (like String, Keyword, etc) which is converted to an atom during compilation. For instance, the String alias translates by default to the atom :"Elixir.String":

iex> is_atom(String)
true
iex> to_string(String)
"Elixir.String"
iex> :"Elixir.String"
String

alias/2지시어(directive)를 사용하면 단순히 어떤 별칭(alias)으로 바꾸고 있습니다.

By using the alias/2 directive, we are simply changing what an alias translates to.

정확히 말하면 Erlang VM에서 (즉 Elixir도) 모듈이 원자형으로 표현되기 때문에 별칭(alias)이 동작할 수 있는 것입니다. 예를들어 Erlang 모듈을 사용할 때의 메커니즘은 이렇습니다:

Aliases work as described because in the Erlang VM (and consequently Elixir), modules are represented by atoms. For example, that's the mechanism we use to call Erlang modules:

iex> :lists.flatten([1,[2],3])
[1, 2, 3]

모듈의 내부의 함수를 동적으로 호출 할 수있는 메커니즘입니다:

This is also the mechanism that allows us to dynamically call a given function in a module:

iex> mod = :lists
:lists
iex> mod.flatten([1,[2],3])
[1,2,3]

다시 말해서, 원자형 :lists의 함수 flatten를 단순히 호출하고 있을뿐입니다.

In other words, we are simply calling the function flatten on the atom :lists.

13.5 중첩 - Nesting

지금까지는 별칭(alias)에 대해 얘기했습니다, Elixir에서 중첩이 어떻게 작동하는지에 대해서도 말씀 드리겠습니다. 다음의 예를 살펴 봅시다:

Now that we have talked about aliases, we can talk about nesting and how it works in Elixir. Consider the following example:

defmodule Foo do
  defmodule Bar do
  end
end

위의 예는 FooFoo.Bar 두 개의 모듈을 정의하고 있습니다. Foo안의 Bar가 같은 lexical scope안에 있는 동안은 Bar만으로도 접근할 수 있습니다. 만약 개발자가 나중에 Bar를 다른 파일로 옮기고 이를 참조하기 위해서는 풀네임(Foo.Bar)을 쓰거나 별칭(alias)이 설정되야 합니다.

The example above will define two modules Foo and Foo.Bar. The second can be accessed as Bar inside Foo as long as they are in the same lexical scope. If later the developer decides to move Bar to another file, it will need to be referenced by its full name (Foo.Bar) or an alias needs to be set using the alias directive discussed above.

다시 말해서 위의 코드는 다음과 같습니다:

In other words, the code above is exactly the same as:

defmodule Elixir.Foo do
  defmodule Elixir.Foo.Bar do
  end
  alias Elixir.Foo.Bar, as: Bar
end

이후 장에서 보겠지만 별칭(alias)은 매크로에서 매우 중요한 역할을 담당합니다. Elixir 모듈에 대해서는 거의 끝나갑니다. 마지막으로 모듈의 특성에 대해 살펴 보겠습니다.

As we will see in later chapters, aliases also play a crucial role in macros, to guarantee they are hygienic. With this we are almost finishing our tour about Elixir modules, the last topic to cover is module attributes.