What resources will make me able to know how the source code of Phoenix or Ecto works?

I know some Elixir and now I’m learning Phoenix, but I want to learn more Elixir, so that for example if I encounter the Ecto.cast somewhere I don’t come to the forum to ask others how this piece of code works but instead I go to changeset.ex:L418 and read the code myself, and know what this function does, how this function is written, how it’s @spec is defined, how a macro somewhere works, etc.

What books and/or tutorials/blogs/youtube-playlists are required to be used to become that fluent in Elixir?

(It’s better if some or all of those resources are free, as I’m a student and here in India one dollar equals to 64 rupees :slight_smile: )

2 Likes

You’ll need to start with the official docs, then read some decent book(s) like Programming Elixir (1.3 / ≥1.6), Elixir in Action, Introducing Elixir, The little Elixir and OTP Guidebook etc and a lot of practice.

The above mentioned books won’t make you automagically a master of the language, but you’d need much more practice and time. If you’re already an experienced programmer in some other language, it may take less time to master your next language (which in your case is Elixir), but if you’re not already experienced in other language(s), it may take more time to master it.

The curiosity level you have is enough (which I assumed from your previous questions and replies), but you’d need to give the language more time (more hours everyday, and more months/years in long term).

And I’m sorry that none of the books I mentioned is free (as you asked in the question), some other answers may come with free resources.

3 Likes

You will need a practice. Find yourself a project which strongly relies on Phoenix or Ecto, and you will have to learn how to read their source :slight_smile:

3 Likes

Thank you @DevotionGeo, thank you @grych!

The Elixir documentation links directly to Erlang’s Dialyzer documentation - and as it happens one of the better Dialyzer introductions is found in Learn You Some Erlang - which of course uses Erlang.

So for a quick introduction to Erlang’s syntax go through (the beginning of) Chapter 2. Introducing Erlang included in the free sample of Designing for Scalability with Erlang/OTP: Implement Robust, Fault-Tolerant Systems.

4 Likes

Thank you @peerreynders, I’ll study the content you linked as soon as I get time! :slight_smile:

For a jumpstart to, for example, Typing Functions.

Create a new project

$ mix new cards
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/cards.ex
* creating test
* creating test/test_helper.exs
* creating test/cards_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd cards
    mix test

Run "mix help" for more commands.
$ cd cards
$ 

In mix.exs change:

defp deps do
  [
    {:dialyxir, "~> 0.5", only: [:dev], runtime: false}
  ]
end

and run

$ mix do deps.get, deps.compile
Running dependency resolution...
Dependency resolution completed:
  dialyxir 0.5.1
* Getting dialyxir (Hex package)
  Checking package (https://repo.hex.pm/tarballs/dialyxir-0.5.1.tar)
  Using locally cached package
==> dialyxir
Compiling 5 files (.ex)
Generated dialyxir app
$

then

$ mix dialyzer
Compiling 1 file (.ex)
Generated cards app
Checking PLT...
[:compiler, :elixir, :kernel, :logger, :stdlib]
Finding suitable PLTs
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Looking up modules in dialyxir_erlang-20.2.2.plt
Finding applications for dialyxir_erlang-20.2.2.plt
Finding modules for dialyxir_erlang-20.2.2.plt
Checking 163 modules in dialyxir_erlang-20.2.2.plt
Finding applications for dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Finding modules for dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Copying dialyxir_erlang-20.2.2.plt to dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Checking 163 modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Adding 228 modules to dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Finding applications for dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Finding modules for dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Copying dialyxir_erlang-20.2.2_elixir-1.6.1.plt to dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Checking 391 modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Adding 58 modules to dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Starting Dialyzer
dialyzer args: [
  check_plt: false,
  init_plt: '/cards/_build/dev/dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt',
  files_rec: ['/cards/_build/dev/lib/cards/ebin'],
  warnings: [:unknown]
]
done in 0m0.87s
done (passed successfully)
$ 

Change the contents of cards/lib/cards.ex to

# cards/lib/cards.ex
defmodule Cards do
  @type suit() :: :spades | :clubs | :hearts | :diamonds
  @type value() :: 1..10 | :j | :q | :k
  @type card() :: {suit(), value()}

  @spec kind(card()) :: :face | :number
  def kind({_,a}) when a >= 1 and a <= 10,
    do: :number
  def kind(_),
    do: :face

  @spec main(list(binary())) :: :ok
  def main(_argv) do
    :number = kind({:spades, 7})
    :face = kind({:spades, :k})
    :number = kind({:rubies, 4}) # should be :diamonds, not :rubies
    :face = kind({:clubs, :q})
    :ok
  end
end

Now run:

$ iex -S mix
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

Compiling 1 file (.ex)
Interactive Elixir (1.6.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Cards.main([])
:ok
iex(2)> 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
a
$ mix dialyzer
Checking PLT...
[:compiler, :elixir, :kernel, :logger, :stdlib]
PLT is up to date!
Starting Dialyzer
dialyzer args: [
  check_plt: false,
  init_plt: '/cards/_build/dev/dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt',
  files_rec: ['/cards/_build/dev/lib/cards/ebin'],
  warnings: [:unknown]
]
done in 0m1.01s
lib/cards.ex:14: Function main/1 has no local return
lib/cards.ex:17: The call 'Elixir.Cards':kind({'rubies',4}) breaks the contract (card()) -> 'face' | 'number'
done (warnings were emitted)
$ 

See also Typespecs.

Alternately:

# lib/cards.ex
defmodule Cards do
  @type suit() :: :spades | :clubs | :hearts | :diamonds
  @type value() :: 1..10 | :j | :q | :k
  @type card() :: {suit(), value()}

  @spec kind(c) :: r when c: card(), r: :face | :number
  def kind({_,a}) when a >= 1 and a <= 10,
    do: :number
  def kind(_),
    do: :face

  @spec main(args) :: r when args: [binary()], r: :ok
  def main(_argv) do
    :number = kind({:spades, 7})
    :face = kind({:spades, :k})
    :number = kind({:rubies, 4}) # should be :diamonds not :rubies
    :face = kind({:clubs, :q})
    :ok
  end
end
4 Likes