From c2ee39454809eaf7ba54704c041c6ac6165caa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kozio=C5=82ek?= Date: Fri, 21 Apr 2017 16:11:00 +0200 Subject: [PATCH] [PL] Update version of Collections lesson (#1059) --- pl/lessons/advanced/protocols.md | 115 +++++++++++++++++++++++++++++++ pl/lessons/basics/collections.md | 2 +- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 pl/lessons/advanced/protocols.md diff --git a/pl/lessons/advanced/protocols.md b/pl/lessons/advanced/protocols.md new file mode 100644 index 0000000000..f6373fd7de --- /dev/null +++ b/pl/lessons/advanced/protocols.md @@ -0,0 +1,115 @@ +--- +layout: page +title: ProtokoĊ‚y +category: advanced +order: 12 +lang: pl +--- + +In this lesson we are going to look at Protocols, what they are, and how we use them in Elixir. + +{% include toc.html %} + +## What Are Protocols +So what are they? +Protocols are a means of achieving polymorphism in Elixir. +One pain of Erlang is extending an existing API for newly defined types. +To avoid this in Elixir the function is dispatched dynamically based on the value's type. +Elixir comes with a number of protocols built in, for example the `String.Chars` protocol is responsible for the `to_string/1` function we've seen used previously. +Let's take a closer look at `to_string/1` with a quick example: + +```elixir +iex> to_string(5) +"5" +iex> to_string(12.4) +"12.4" +iex> to_string("foo") +"foo" +``` + +As you can see we've called the function on multiple types and demonstrated that it work on them all. +What if we call `to_string/1` on tuples (or any type that hasn't implemented `String.Chars`)? +Let's see: + +```elixir +to_string({:foo}) +** (Protocol.UndefinedError) protocol String.Chars not implemented for {:foo} + (elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1 + (elixir) lib/string/chars.ex:17: String.Chars.to_string/1 +``` + +As you can see we get a protocol error as there is no implementation for tuples. +In the next section we'll implement the `String.Chars` protocol for tuples. + +## Implementing a protocol + +We saw that `to_string/1` has not yet been implemented for tuples, so let's add it. +To create an implementation we'll use `defimpl` with our protocol, and provide the `:for` option, and our type. +Let's take a look at how it might look: + +```elixir +defimpl String.Chars, for: Tuple do + def to_string(tuple) do + interior = + tuple + |> Tuple.to_list + |> Enum.map(&Kernel.to_string/1) + |> Enum.join(", ") + + "{#{interior}}" + end +end +``` + +If we copy this into IEx we should be now be able to call `to_string/1` on a tuple without getting an error: + +```elixir +iex> to_string({3.14, "apple", :pie}) +"{3.14, apple, pie}" +``` + +We know how to implement a protocol but how do we define a new one? +For our example we'll implement `to_atom/1`. +Let's see how to do that with `defprotocol`: + +```elixir +defprotocol AsAtom do + def to_atom(data) +end + +defimpl AsAtom, for: Atom do + def to_atom(atom), do: atom +end + +defimpl AsAtom, for: BitString do + defdelegate to_atom(string), to: String +end + +defimpl AsAtom, for: List do + defdelegate to_atom(list), to: List +end + +defimpl AsAtom, for: Map do + def to_atom(map), do: List.first(Map.keys(map)) +end +``` + +Here we've defined our protocol and it's expected method, `to_atom/1`, along with implementations for a few types. +Now that we have our protocol, let's put it to use in IEx: + +```elixir +iex> import AsAtom +AsAtom +iex> to_atom("string") +:string +iex> to_atom(:an_atom) +:an_atom +iex> to_atom([1, 2]) +:"\x01\x02" +iex> to_atom(%{foo: "bar"}) +:foo +``` + +It is worth nothing that although underneath structs are Maps, but they do not share protocol implementations with Maps. They are not enumerable, they cannot be accessed. + +As we can see, protocols are a powerful way to achieve polymorphism. diff --git a/pl/lessons/basics/collections.md b/pl/lessons/basics/collections.md index fa15659c78..859be292d3 100644 --- a/pl/lessons/basics/collections.md +++ b/pl/lessons/basics/collections.md @@ -1,5 +1,5 @@ --- -version: 0.9.0 +version: 1.0.0 layout: page title: Kolekcje category: basics