   option when opening the file and then all other functions from
   `IO` are available, since they work directly with Unicode data.
 
+  `modes_or_function` can either be a list of modes or a function. If it's a
+  list, it's considered to be a list of modes (that are documented below). If
+  it's a function, then it's equivalent to calling `open(path, [],
+  modes_or_function)`. See the documentation for `open/3` for more information
+  on this function.
+
   The allowed modes:
 
     * `:binary` - opens the file in binary mode, disabling special handling of unicode sequences

  """
  @spec open(Path.t, [mode | :ram]) :: {:ok, io_device} | {:error, posix}
  @spec open(Path.t, (io_device -> res)) :: {:ok, res} | {:error, posix} when res: var
  def open(path, modes \\ [])

  def open(path, modes) when is_list(modes) do
    F.open(IO.chardata_to_string(path), normalize_modes(modes, true))


  Returns the IO device otherwise.

  See `open/2` for the list of available modes.
  """
  @spec open!(Path.t, [mode | :ram]) :: io_device | no_return
  @spec open!(Path.t, (io_device -> res)) :: res | no_return when res: var
  def open!(path, modes_or_function \\ []) do
    case open(path, modes_or_function) do
      {:ok, io_device_or_function_result} ->
        io_device_or_function_result
      {:error, reason} ->
        raise File.Error, reason: reason, action: "open", path: IO.chardata_to_string(path)
    end
