Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you check for the type of variable in Elixir

Tags:

elixir

People also ask

How do you check what type a variable is?

To check the type of a variable, you can use the type() function, which takes the variable as an input. Inside this function, you have to pass either the variable name or the value itself. And it will return the variable data type.

How do you define a variable in Elixir?

Variable Naming Naming variables follow a snake_case convention in Elixir, i.e., all variables must start with a lowercase letter, followed by 0 or more letters(both upper and lower case), followed at the end by an optional '?' OR '!' .

What is an atom in Elixir?

What Is an Atom in Elixir and How Are They Stored? An atom is one of the basic types in Elixir. They are named constants, and their value is their name. Atoms are great for sending messages and representing constants; they're meant to be used as a developer tool.

Is Elixir a string?

Strings in Elixir are a sequence of Unicode characters, typically written between double quoted strings, such as "hello" and "héllò" . In case a string must have a double-quote in itself, the double quotes must be escaped with a backslash, for example: "this is a string with \"double quotes\"" .


Starting in elixir 1.2 there is an i command in iex that will list the type and more of any Elixir variable.

iex> foo = "a string" 
iex> i foo 
Term
 "a string"
Data type
 BitString
Byte size
 8
Description
 This is a string: a UTF-8 encoded binary. It's printed surrounded by
 "double quotes" because all UTF-8 encoded codepoints in it are        printable.
Raw representation
  <<97, 32, 115, 116, 114, 105, 110, 103>>
Reference modules
  String, :binary

If you look in the code for the i command you'll see that this is implemented via a Protocol.

https://github.com/elixir-lang/elixir/blob/master/lib/iex/lib/iex/info.ex

If you want to implement a function for any Data type in Elixir, the way to do that is to define a Protocol and implementation of the Protocol for all the data types you want the function to work on. Unfortunately, you can't use a Protocol function in guards. However, a simple "type" protocol would be very straightforward to implement.


There's no direct way to get the type of a variable in Elixir/Erlang.

You usually want to know the type of a variable in order to act accordingly; you can use the is_* functions in order to act based on the type of a variable.

Learn You Some Erlang has a nice chapter about typing in Erlang (and thus in Elixir).

The most idiomatic way to use the is_* family of functions would probably be to use them in pattern matches:

def my_fun(arg) when is_map(arg), do: ...
def my_fun(arg) when is_list(arg), do: ...
def my_fun(arg) when is_integer(arg), do: ...
# ...and so on

Also for debugging purposes, if you're not in iex, you can call it directly:

IEx.Info.info(5)
=> ["Data type": "Integer", "Reference modules": "Integer"]

I'll just leave this here for the sake of somebody hopefully figuring out an actually sane version. At the moment there are no good answers to this coming up on google...

defmodule Util do
    def typeof(self) do
        cond do
            is_float(self)    -> "float"
            is_number(self)   -> "number"
            is_atom(self)     -> "atom"
            is_boolean(self)  -> "boolean"
            is_binary(self)   -> "binary"
            is_function(self) -> "function"
            is_list(self)     -> "list"
            is_tuple(self)    -> "tuple"
            true              -> "idunno"
        end    
    end
end

For the sake of completeness, test cases:

cases = [
    1.337, 
    1337, 
    :'1337', 
    true, 
    <<1, 3, 3, 7>>, 
    (fn(x) -> x end), 
    {1, 3, 3, 7}
]

Enum.each cases, fn(case) -> 
    IO.puts (inspect case) <> " is a " <> (Util.typeof case)
end

Here's a solution with protocols; I am not sure if they are faster(I sure hope they are not doing a loop over all types), but it is pretty ugly(and fragile; if they add or remove a basic type or rename, it will break it).

defprotocol Typeable, do: def typeof(self)
defimpl Typeable, for: Atom, do: def typeof(_), do: "Atom"
defimpl Typeable, for: BitString, do: def typeof(_), do: "BitString"
defimpl Typeable, for: Float, do: def typeof(_), do: "Float"
defimpl Typeable, for: Function, do: def typeof(_), do: "Function"
defimpl Typeable, for: Integer, do: def typeof(_), do: "Integer"
defimpl Typeable, for: List, do: def typeof(_), do: "List"
defimpl Typeable, for: Map, do: def typeof(_), do: "Map"
defimpl Typeable, for: PID, do: def typeof(_), do: "PID"
defimpl Typeable, for: Port, do: def typeof(_), do: "Port"
defimpl Typeable, for: Reference, do: def typeof(_), do: "Reference"
defimpl Typeable, for: Tuple, do: def typeof(_), do: "Tuple"

IO.puts Typeable.typeof "Hi"
IO.puts Typeable.typeof :ok

Another approach is to use pattern matching. Say you're using Timex, which uses a %DateTime{} struct, and you want to see if an element is one. You can find a match using pattern matching in the method.

def datetime?(%DateTime{}) do
  true
end

def datetime?(_) do
  false
end