Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question mark and "is_" in Elixir function names

Tags:

elixir

I'm reading the naming convention for Elixir. It states:

The names of predicate functions that cannot be used within guards should have a trailing question mark (?) rather than the is_ (or similar) prefix.

Hence, what kind of functions can't be used in guard?

like image 289
Kevin Avatar asked Feb 20 '17 09:02

Kevin


2 Answers

All three of those functions contain expressions that are valid in guards; it's just that custom guards must be written as macros, not normal functions:

defmodule User do
  defstruct age: 0

  defmacro kid?(age) do
    quote do
      6 < unquote(age) and unquote(age) < 12
    end
  end

  defmacro teen?(age) do
    quote do
      12 < unquote(age) and unquote(age) < 18
    end
  end

  defmacro elder?(age) do
    quote do
      60 < unquote(age)
    end
  end
end

defmodule Greeting do
  import User

  def greet(%{age: age}) when kid?(age), do: "Hiya"
  def greet(%{age: age}) when teen?(age), do: "Whatever"
  def greet(%{age: age}) when elder?(age), do: "You kids get off my lawn"
  def greet(_), do: "Hello"
end

for age <- [0, 5, 10, 15, 20, 90] do
  IO.inspect {age, Greeting.greet(%{age: age})}
end

Output:

{0, "Hello"}
{5, "Hello"}
{10, "Hiya"}
{15, "Whatever"}
{20, "Hello"}
{90, "You kids get off my lawn"}
like image 142
Dogbert Avatar answered Nov 15 '22 07:11

Dogbert


From the Elixir 1.7.3 documentation: (bold is mine)

As mentioned before, only the expressions listed in this page are allowed in guards. However, we can take advantage of macros to write custom guards that can simplify our programs or make them more domain-specific. At the end of the day, what matters is that the output of the macros (which is what will be compiled) boils down to a combinations of the allowed expressions.

and from Naming Conventions doc,:

Trailing question mark (foo?) Functions that return a boolean are named with a trailing question mark. Examples: Keyword.keyword?/1, Mix.debug?/0, String.contains?/2 However, functions that return booleans and are valid in guards follow another convention, described next.

is_ prefix (is_foo) Type checks and other boolean checks that are allowed in guard clauses are named with an is_ prefix. Examples: Integer.is_even/1, Kernel.is_list/1 These functions and macros follow the Erlang convention of an is_ prefix, instead of a trailing question mark, precisely to indicate that they are allowed in guard clauses. Note that type checks that are not valid in guard clauses do not follow this convention. Examples: Keyword.keyword?/1, Regex.regex?/1

So, using one of the listed expressions that returns a boolean is ok for write compliant guard macros (if they haven't side effects).

like image 32
Guido Avatar answered Nov 15 '22 07:11

Guido