 
   ## Examples
 
-  In Elixir, only `false` and `nil` are considered falsy values.
-  Everything else evaluates to `true` in `if/2` clauses. Depending
-  on the application, it may be important to specify a `blank?`
-  protocol that returns a boolean for other data types that should
-  be considered "blank". For instance, an empty list or an empty
-  binary could be considered blank.
-
-  Such protocol could be implemented as follows:
-
-      defprotocol Blank do
-        @doc "Returns `true` if `data` is considered blank/empty"
-        def blank?(data)
-      end
-
-  Now that the protocol is defined it can be implemented. It needs to be
-  implemented for each Elixir type; for example:
-
-      # Integers are never blank
-      defimpl Blank, for: Integer do
-        def blank?(number), do: false
-      end
-
-      # The only blank list is the empty one
-      defimpl Blank, for: List do
-        def blank?([]), do: true
-        def blank?(_),  do: false
-      end
-
-      # The only blank atoms are "false" and "nil"
-      defimpl Blank, for: Atom do
-        def blank?(false), do: true
-        def blank?(nil),   do: true
-        def blank?(_),     do: false
-      end
-
-  The implementation of the `Blank` protocol would need to be defined for all
-  Elixir types. The available types are:
+  In Elixir, we have two verbs for checking how many items there
+  are in a data structure: `length` and `size`.  `length` means the
+  information must be computed. For example, `length(list)` needs to
+  traverse the whole list to calculate its length. On the other hand,
+  `tuple_size(tuple)` and `byte_size(binary)` do not depend on the
+  tuple and binary size as the size information is precomputed in
+  the data structure.
+
+  Although Elixir includes specific functions such as `tuple_size`,
+  `binary_size` and `map_size`, sometimes we want to be able to
+  retrieve the size of a data structure regardless of its type.
+  In Elixir we can write polymorphic code, i.e. code that works
+  with different shapes/types, by using protocols. A size protocol
+  could be implemented as follows:
+
+      defprotocol Size do
+        @doc "Calculates the size (and not the length!) of a data structure"
+        def size(data)
+      end
+
+  Now that the protocol can be implemented for every data structure
+  the protocol may have a compliant implementation for:
+
+      defimpl Size, for: Binary do
+        def size(binary), do: byte_size(binary)
+      end
+
+      defimpl Size, for: Map do
+        def size(map), do: map_size(map)
+      end
+
+      defimpl Size, for: Tuple do
+        def size(tuple), do: tuple_size(tuple)
+      end
+
+  Notice we didn't implement it for lists as we don't have the
+  `size` information on lists, rather its value needs to be
+  computed with `length`.
+
+  It is possible to implement protocols for all Elixir types:
 
     * Structs (see below)
     * `Tuple`

  all implementations are known up-front, Elixir provides a feature
  called protocol consolidation. For this reason, all protocols are
  compiled with `debug_info` set to `true`, regardless of the option
  set by `elixirc` compiler. The debug info though may be removed
  after consolidation.

  For more information on how to apply protocol consolidation to
  a given project, please check the functions in the `Protocol`
  module or the `mix compile.protocols` task.
  """
  defmacro defprotocol(name, do_block)


      defmodule User do
        defstruct [:email, :name]

        defimpl Size do
          def size(%User{}), do: 2 # two fields
        end
      end

  If a protocol implementation is not found for a given type,
  invoking the protocol will raise unless it is configured to
  fallback to `Any`. Conveniences for building implementations
  on top of existing ones are also available, look at `defstruct/1`
  for more information about deriving
  protocols.

  ## Fallback to any

  In some cases, it may be convenient to provide a default
  implementation for all types. This can be achieved by setting
  the `@fallback_to_any` attribute to `true` in the protocol
  definition:

      defprotocol Size do
        @fallback_to_any true
        def size(data)
      end

  The `Size` protocol can now be implemented for `Any`:

      defimpl Size, for: Any do
        def size(_), do: 0
      end

  Although the implementation above is arguably not a reasonable
  one. For example, it makes no sense to say a PID or an Integer
  have a size of 0. That's one of the reasons why `@fallback_to_any`
  is an opt-in behaviour. For the majority of protocols, raising
  an error when a protocol is not implemented is the proper behaviour.

  ## Types

  Defining a protocol automatically defines a type named `t`, which
  can be used as follows:

      @spec print_size(Size.t) :: :ok
      def print_size(data) do
        IO.puts(case Size.size(data) do
          0 -> "data has no items"
          1 -> "data has one item"
          n -> "data has #{n} items"
        end)
      end

  The `@spec` above expresses that all types allowed to implement the
