Elixir Pocket Syntax - short snippets to make your life easier

wiki
#1

This is a wiki - anyone at Trust Level 1 or higher can help keep it updated.

Elixir Pocket Syntax

Uncommon Logical stuff of Elixir modules,definitions and some coding snippets that makes our life easy.

1. Creating Private Functions

Code

defp defname(arguments) do
  # your definition goes here 
end

Example

defmodule MyModule do
  @doc "This is the public function can be called out side"
  def public_function do
    IO.puts "I am a public function"
  end

  defp private_function do
    IO.puts "I am private function"
  end
end

Description

Here defp stands for the private function which means you cannot call that function out side module by importing like this MyModule.private_function.This can be used only inside the another functions in the module it has been defined in. In our example it can be called inside the public_function.

2. Pipe Operations `|>’

Code

id |> getName() |> toUpperCase()

Example

defmodule MyModule do
  def function do
    admin = getNameById(id) |> toUpperCase |> isAdmin
    IO.puts admin
  end
end

Description

Here the out put of the getNameById is passed as the first parameter to the toUpperCase in which it returns name as all capitals letters and that name is passed to the isAdmin function to check that the person is admin or not finally a boolean true or false is returned.

The only thing |> does, is to take the return value of the left-hand-side and insert it as first argument in the function on the right-hand-side. This allows you to write above example, instead of writing:

isAdmin(toUpperCase(getNameById(id)))

As above example reads left-to-right (or top-to-bottom), this is more natural to read.

In a typical “object-oriented” language, the code to achieve a similar aim would look like this:

getNameById(id).toUpperCase().isAdmin()

So, you can think of |> as being the Elixir version of . (though without the class lookup).

3. Import specific functions

Code

import :math, only: [sqrt: 1]
import :math, except: [sin: 1, cos: 1]

Example

defmodule MyModule do
  import :math, only: [sqrt: 1]

  def function do
    sqrt 4
  end
end

Description

In the above example only the sqrt function is loaded is imported to the the module. This means that this specific function can be accessed like sqrt(4) (or, without the brackets, sqrt 4). All other functions, even ones in the :math module still need to be accessed by prefixing the full module name, such as :math.sin(2).

4. Functions with Default Values

Code

def fall_velocity(distance, gravity \\ 9.8) do
  # code
end

Example

import :math, only: [sqrt: 1]
defmodule MyModule do
  def fall_velocity(distance, gravity \\ 9.8) do
    velocity=sqrt 2*gravity*distance
    IO.puts "the falling velocity is #{velocity}"
  end
end

Description

By adding default arguments, Elixir underwater adds multiple versions of the function for you, with different arities (taking a different amount of parameters). In above example, a fall_velocity/1 and a fall_velocity/2 is defined. The underwater implementation of fall_velocity/1 is as follows:

def fall_velocity(distance), do: fall_velocity(distance, 9.8)

So: the shorter version(s) of a function will call the longest version with the later argument(s) filled in with the specified default value(s).

Defaults With Pattern-Matching

If your function has multiple clauses, it must have a function head (like a clause without a body), and the default(s) must be defined only there.

Example

defmodule MyModule do
  def greet(name, greeting \\ "Hello")

  def greet("", _) do
    IO.puts "Please tell me your name."
  end

  def greet(name, greeting) do
    IO.puts "#{greeting}, #ecto::tag name}"
  end
end

5. Documentation and specifications

Code

defmodule Mymdule do
  @moduledoc """
  Explanation about the module
  """

  @vsn 0.1 # module version

  @doc """
    your documentation here can have multiple 
    lines of text 
    line1
    line2 
    etc
  """
  @spec function_name(number()) :: number()
  def function_name do
    # code
  end
end

How to use?

h(Modulename.function_name)
s(Modulename.function_name)

Description

Here h() stands for help when you type like that you will be displayed with the @doc text and similarly when you type s() you will be getting the function specifications it explains what parameters has to pass and what it returns when you call or simply what has to give to the function and what it will give in return.

6. Using Erlang From Elixir

Code

:application.which_applications
:erlang.module_info

Description

here the list_applications returns the list of applications being executed in an Erlang VM .This is the way to use the function from Elixir.
The erlang would be like this

application:which_applications() # moduleName:functionName() 

7. Observer GUI

Code

:observer.start

Description

You will see the Graphical representation of all process and sub prcesses.

8. Single Line definitions

Code

defmodule MyModule do
  def callme, do: IO.puts "This is the single line definition"
  # no need of end here
end

# one line with module (useful in iex):
defmodule MyModule, do: def callme, do: IO.puts "This is the single line definition"

Explanation

The definition name and do block are separated by the ,and no end after the do statement.

9. Single Line if

Code

message = if condition, do: "condition returns false", else: "otherwise"
IO.puts "This prints when #{message}"

10. Aliases

You can define the aliases in two ways

Code

defmodule MyModule do
  alias Geometry.Rectangle, as: Rectangle

  def my_function do
    Rectangle.area({1, 2}, {3, 4})
  end
end
#The above style is most formal one 

defmodule MyModule do
  alias Geometry.Rectangle

  def my_function do
    Rectangle.area({1, 2}, {3, 4})
  end
end
#This is the fast style of aliasing .

Explanation

This line alias Geometry.Rectangle, as: Rectangle of code states that we are naming the alias with name Rectangle You can any kinda name but adding the last name of the module scope is too good choice. By default if you don’t specify the any value for as:something then it assigns the default one i.e the last scope in name here Rectangle

11. String inner inner binary representation

A common trick in Elixir is to concatenate the null byte <<0>> to a string to see its inner binary representation:

Code

iex> "hełło" <> <<0>>
<<104, 101, 197, 130, 197, 130, 111, 0>>

12. Specifying the binary

Code

<<variable::size>>
<<2::4, 4::5>> # this is the 4+5=9 bits binary
<<2::size(4), 4::size(4)>> 
# both are same 

If you do not the size of the binary you can make call some thing like this

<<x::4, y::binary>>

Explanation

The above code line states that first 4 bits are to stored in the x variable. The remaining bits we are storing as the binary blocks in the the variable y which means that rest of the length should multiply by the number 8 as the binary means 8 bits.The size of the tail must be evenly divisible by 8.

<<x::4, y::binary, t::5>> This is the wrong representation, It raised the compilation error . The unsized binary should be at the last i mean tail of the string as followed <<x::4, t::5, y::binary>>

13. Importing constants to another module

defmodule Constants do
  @moduledoc false
  # This module contains compile time constants so that they don't have to be
  # defined in multiple places, but don't also have to be built up repeatedly.

  @doc false
  defmacro __using__(_) do
    quote do
      @constant1 10000
      @constant2 20000
    end
end

Explanation

Here you need to define macro __using__to define the constants. In side the module just use Contants

Code

defmodule MyModule do
  use Constants

  def calleme, do: IO.puts "constant 1 value = #{@constant1}"
end

Note

make sure both are at the same hierarchy . According to you above code.If you need you can change but be sure you have to change the use path/to/module/ also :thanks:

14. Updating maps

Consider that you have Map like the below one I have shown …

person = %{name: "John", age: 22, place: "York Street"}

Here if you want to change the name field of the person map , you can simply do like this.

new_person = %{person | name: "Jopra"}

You see that actually It won’t rewrite the person data it gives you the new copy of the person data with the name field changing to our update . The person data is immutable here.
You can also update multiple keys here unlike the firsr example I have shown on this snippet.

new_person = %{person | name: "Jopra", age: "secret"}

15 hd and tl list functions

list = [1,2,3,4,5]
hd list # returns the first element in the list    1
tl list # returns the tail list i.e only the tail part of the list  [2,3,4,5]

17 Likes

#3

Hey! This seems like a nice collection of resources.

However, if you’re going to present this kind of information for new people you should make sure to use common Elixir conventions throughout your code. This includes things like:

  • Indentation. Indentation should be 2 spaces
  • snake case vs camel case: new_person is the convention, vs newPerson

There’s also some things here that are a bit confusing.

What does this mean? What is getNameById(id).toUpperCase().isAdmin()?

This is not an example of importing.

There’s a lot of spelling errors and formatting inconsistencies as well. I think a lot of the stuff here is really great, and I appreciate the effort you put into it. I think with a few tweaks and clarifications this could be very useful for people.

1 Like

#4

Yea , I will consider all the factors you have mentioned.
Thanks for the FeedBack

1 Like

#5

Those are great suggestions. The only one that called my attention on this one.

If a module needs to exports constants, then it would be preferable to simply list those constants as functions and any other piece of code may call it as necessary.

2 Likes

#6
defmodule myModule do
    def function() do
        admin = getNameById id |> toUpperCase |> isAdmin
        IO.puts admin
    end
end

getNameById(id).toUpperCase().isAdmin()

Your “description” looks like you want to call toUppercase() on the result of getNameById(id), while your example does something different! It does first pass id to toUppercase and that result to isAdmin and finally passes that result to getNameById.

Just look at the following example in iex:

iex(1)> IO.inspect 1 |> to_string  # What you have written
"1"   # this line was printed
"1"   # this line shows what was returned
iex(2)> IO.inspect(1) |> to_string # What you have described
1     # This line was printed
"1"   # This line shows what was returned

Parenthesises are optional but important.

2 Likes

#7

Pipe operator has higher precedence, so

getNameById id |> toUpperCase
#well actually become
getNameById(toUpperCase(id))

Use

admin = getNameById(id) |> toUpperCase
#or
admin = id |> getNameById |> toUpperCase

to generate

getNameById(id).toUpperCase()
3 Likes

#8

You can easily see how the code will be grouped with quote and Macro.to_string:

iex(1)> quote(do: foo 1 |> bar()) |> Macro.to_string |> IO.puts
foo(1 |> bar())
:ok
iex(2)> quote(do: foo(1) |> bar()) |> Macro.to_string |> IO.puts
foo(1) |> bar()
:ok
8 Likes

#9

Nice one @blackode :023:

Are you happy for me to turn this into a wiki so that others can help edit/add to it?

I also agree with @benwilson512 about Elixir conventions, removing camelCase where it’s generally not used is a particular necessity.

2 Likes

#10

Comment syntax is #, so this:

@vsn 0.1 # module version

Also on:

Should be:

@moduledoc """
Explanation about the module
"""

So the closing "" becomes """.

:slight_smile:

2 Likes

#11

Ok this is now a wiki :slight_smile:

Please feel free to edit/append to it :023: (Trust Level 1 or higher members can edit wikis).

1 Like

#12

Could you give your reasoning for this? Constants were one of the topics (the only I think?) that I found lacking when learning about Elixir. I ended up doing a elixir constants concept app where I tried to compare/contrast the various methods that I came across. (I ended up doing a SO Documentation for it to test out that SO beta feature, got no feedback, and I forgot about it until your comment.) :thinking:

The primary reason I ended up not using functions is to enable sharing project-wide constants in guards.

1 Like

#13

Functions are the most natural way of sharing data and functionality between modules.

Unless you have a really large amount of constants, I would do the below whenever you need to share constants between modules:

@foo MyApp.Constant.foo
@bar MyApp.Constant.bar

For a large amount of constants you may need in guards, then using a macro that injects modules attributes is possibly OK.

2 Likes

#14

Regarding to @lexmag An opinionated Elixir style guide I updated this wiki and fixed also some other wiki things like numeration of all headers (level 3).

2 Likes

#15

@blackode Thanks for this, just a small typo to fix: In section 3, where you have

defmodule MyModule do
  import :math, only; [sqrt: 1] 

there’s a semi-colon after only which should be a colon. :slight_smile:

2 Likes

#16

Thanks for noticing that … :clap: will correct that typo mistake

2 Likes

#17

@blackode some time ago I found Elixir Recipes, perhaps you could try to contribute there as well :slight_smile: :slight_smile:

1 Like

#18

Thanks for the Elixir Recipes. That is really Great . Thanks again for bringing that to me.

2 Likes

#19

Elixir Tips

4 Parts Killer Elixir Tips

Each Part Holds the 10 Unique Tips and Tricks with live Examples…

1 Like

#20

This looks simpler:

iex(1)> [a,b,c,d | rest] = [1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
iex(2)> {a,b,c,d}
{1, 2, 3, 4}
iex(3)> rest
[5, 6, 7]
iex(4)> 

Compared to: Section 5:2 “Picking out the elements in List”

iex> [first | [second | [third | [ fourth | _rest ]]]] = [1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
iex> first
1
iex> {second, third, fourth}
{2, 3, 4}
iex(5)>
1 Like