Elixir 1.4.0 Preview

January 10, 2017

1월 5일, Elixir 1.4.0이 릴리스되었습니다. 어떤 것이 추가되고, 어떤 변경이 있었는지 살펴보도록 하죠.

Registry

Elixir의 표준 라이브러리에 Registry라는 모듈이 추가되었습니다. 한 문장으로 간단하게 요약해보자면 분산되고 확장 가능한 키-값 저장소입니다. 이는 프로세스 이름을 다루거나 디스패쳐, pub-sub 시스템을 간단하게 구현할 수 있게 해줍니다. Elixir Tutorial을 진행해보았다면, 또는 이와 비슷한 기능을 구현해보신 적이 있다면 금방 이해하실 수 있을 겁니다. 이전까지였다면 etsGenServer를 이용해서 직접 구현해야 했습니다. Registry 모듈은 다음과 같은 특징을 가지고 있습니다.

Options

레지스트리를 만들때에 두가지 옵션이 있습니다.

:via

프로세스의 이름 레지스트리를 사용하는 경우, 프로세스를 생성(i.e. start_link)한 뒤, 프로세스를 레지스트리에 등록하게 됩니다. 매번 이렇게 등록하는 것도 귀찮습니다. 그래서 :via라는 옵션이 Registry 모듈과 함께 추가되었는데요. 우선 코드를 보시죠.

{:ok, _} = Registry.start_link(:unique, Registry.ViaTest)
name = {:via, Registry, {Registry.ViaTest, "agent"}}
{:ok, _} = Agent.start_link(fn -> 0 end, name: name)
Agent.get(name, & &1)
#=> 0
Agent.update(name, & &1 + 1)
Agent.get(name, & &1)
#=> 1

{:via, Registry, {registry, key}} 라는 튜플을 만들어서 start_link에 프로세스 이름 대신 넘겨줍니다. 그러면 짠! 마법처럼 프로세스가 생성됩니다. 코드에서 일어난 일을 설명하자면, ‘agent’라는 키에 프로세스가 등록되어 있지 않다면, 그 키에 새 프로세스를 만든 뒤, 등록합니다. 그리고 그 뒤로 사용할 때에도 레지스트리를 통해서 프로세스에 접근할 수 있습니다. 이미 키에 프로세스가 등록되어 있다구요? 그 경우 start_link{:error, {:already_started, current_pid}}를 반환하게 됩니다.

dispatch

dispatch를 사용하여 디스패쳐인 것처럼 사용할 수도 있습니다. 역시 코드를 봅시다.

{:ok, _} = Registry.start_link(:duplicate, Registry.DispatcherTest)
{:ok, _} = Registry.register(Registry.DispatcherTest, "hello", {IO, :inspect})
Registry.dispatch(Registry.DispatcherTest, "hello", fn entries ->
  for {pid, {module, function}} <- entries, do: apply(module, function, [pid])
end)
# Prints #PID<...> where the pid is for the process that called register/3 above
#=> :ok

Elixir는 어디랑은 다르게 공식 문서가 참 친절하고 보기 좋아서 행복합니다.

Pub-sub을 만들어 볼까요?

{:ok, _} = Registry.start_link(:duplicate, Registry.PubSubTest,
                               partitions: System.schedulers_online)
{:ok, _} = Registry.register(Registry.PubSubTest, "hello", [])
Registry.dispatch(Registry.PubSubTest, "hello", fn entries ->
  for {pid, _} <- entries, do: send(pid, {:broadcast, "world"})
end)
#=> :ok

좋네요. XD

Task.async_stream

collection
|> Enum.map(&Task.async(SomeMod, :function, [&1]))
|> Enum.map(&Task.await/1)

이런 코드를 작성하는 경우가 가끔 있습니다. 이 코드의 좋지 않은 부분은 두 가지입니다.

전자의 경우, 동시에 처리할 수 있는 숫자를 제한하고 싶은 경우가 있을 겁니다. Task.async_streammax_concurrency 옵션을 통해서 이러한 상황을 제어할 수 있게 도와줍니다.

collection
|> Task.async_stream(SomeMod, :function, [], max_concurrency: 8)
|> Enum.to_list()

해당 함수들은 지연 평가되며, 특정 슈퍼바이저 하에서 실행하고 싶다면 Task.Supervisor.async_stream을 사용하면 됩니다.

Application inference

deps에 포함되어 있는 의존성의 경우, application에 명시하지 않더라도 Mix에서 자동으로 가져올 수 있게 되었습니다.

def application do
  [applications: [:logger, :plug, :postgrex]]
end

def deps do
  [{:plug, "~> 1.2"},
   {:postgrex, "~> 1.0"}]
end

이랬던 설정을,

def application do
  [extra_applications: [:logger]]
end

def deps do
  [{:plug, "~> 1.2"},
   {:postgrex, "~> 1.0"}]
end

이렇게 작성할 수 있게 됩니다. deps에 포함되지만 가져오고 싶지 않은 의존성은 runtime: false를 이용해주세요.

Deprecations

Soft deprecations

이 제거 예정 목록은 약한 제거 예정입니다. 다시 말해서, 아직 deprecated 경고를 보여주지 않으며, 문서를 생성하지 않도록 변경된 경우도 있습니다.

Deprecations

Enhancements

Date.compare/2, Time.compare/2, NaiveDateTime.compare/2, DateTime.compare/2 추가

날짜를 비교하기 위한 함수들이 추가되었습니다. 값을 받아서 비교한뒤, 앞의 인자가 작으면 :lt, 같으면 :eq, 크면 :gt를 반환합니다. 다른 타입의 날짜간에도 비교가 가능하며, 호출한 compare의 모듈에 따라서 비교하는 값이 달라집니다.

iex> Date.compare(~D[2016-04-16], ~N[2016-04-28 01:23:45])
:lt
iex> Date.compare(~D[2016-04-16], ~N[2016-04-16 01:23:45])
:eq
iex> Date.compare(~N[2016-04-16 12:34:56], ~N[2016-04-16 01:23:45])
:eq

여기에서는 Date.compare/2이므로 날짜만을 보고 비교합니다.

NaiveDateTime.add/2, NaiveDateTime.diff/2 추가

NaiveDateTime을 가공하기 위한 함수가 추가되었습니다. 이름만으로도 내용은 충분히 추측이 가능하죠? 두번째 인자로는 첫번째 값의 단위를 지정할 수 있습니다.

iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], -2)
~N[2014-10-02 00:29:08]
# can work with other units
iex> NaiveDateTime.add(~N[2014-10-02 00:29:10], 2_000, :millisecond)
~N[2014-10-02 00:29:12]

iex> NaiveDateTime.diff(~N[2014-10-02 00:29:12], ~N[2014-10-02 00:29:10])
2
iex> NaiveDateTime.diff(~N[2014-10-02 00:29:12], ~N[2014-10-02 00:29:10], :microsecond)
2_000_000

Etc

Etc

Syntax coloring

이제 IEx 세션에서 데이터를 보여줄때 각 요소별로 색상이 다르게 보입니다! 이제 눈이 빠져라 화면을 쳐다보지 않아도 됩니다

Screenshot

이 스크린샷은 여기에서 끌어왔습니다. 각각의 색상은 :syntax_colors 옵션을 사용하여 변경할 수 있습니다.

IEx.configure [colors: [syntax_colors: [atom: :cyan, string: :green]]]

Mix install from SCM

escript를 mix를 통하여 직접 설치할 수 있게 되었습니다.

mix escript.install hex ex_doc

이런 느낌. PATH에 ~/.mix/escripts를 추가하면 ex_doc을 실행할 수 있게 됩니다.

Conclusion

개인적으로는 꽤나 괜찮아보이는 개선이 많이 보이는데 어떠셨나요? 앞으로는 Elixir 1.4와 함께 즐거운 개발하세요. XD

Reference