{"id":16058840,"url":"https://github.com/andyatkinson/elixir-getting-started","last_synced_at":"2025-06-21T03:38:42.333Z","repository":{"id":66952262,"uuid":"80391937","full_name":"andyatkinson/elixir-getting-started","owner":"andyatkinson","description":"Learning Elixir and Phoenix","archived":false,"fork":false,"pushed_at":"2017-03-21T02:17:03.000Z","size":90,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-01T17:48:17.267Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andyatkinson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-30T03:50:15.000Z","updated_at":"2019-07-09T15:54:11.000Z","dependencies_parsed_at":"2023-05-15T18:15:08.333Z","dependency_job_id":null,"html_url":"https://github.com/andyatkinson/elixir-getting-started","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andyatkinson/elixir-getting-started","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyatkinson%2Felixir-getting-started","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyatkinson%2Felixir-getting-started/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyatkinson%2Felixir-getting-started/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyatkinson%2Felixir-getting-started/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andyatkinson","download_url":"https://codeload.github.com/andyatkinson/elixir-getting-started/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andyatkinson%2Felixir-getting-started/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261058649,"owners_count":23103888,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-09T03:40:48.212Z","updated_at":"2025-06-21T03:38:37.317Z","avatar_url":"https://github.com/andyatkinson.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"http://elixir-lang.org/\n\n##### Console\n\n`iex`\n\n#### Notes\n\nAtoms are like symbols. e.g. `:hello`\nStrings are encoded in UTF-8.\nStrings are represented by binaries which are a sequence of bytes\n\nString module contains helpers, e.g. `String.upcase(\"hello\")`\n\n##### Anonymous functions\nCan be created inline. Delimited by `fn` and `end`\n\nadd = fn a, b -\u003e a + b end\n\ndot (\".\") is required to invoke an anonymous function. Dot ensures there is no ambiguity between calling an anonymous function and a named function of the same name.\n\n\n##### Lists\n\nConcat (`++`) or subtract (`--`)\n\n++/2 and --/2 operators\n\ne.g. [1]++[2] or [1,2]--[1]\n\nLinked list, head and tail of list\n\n```\nlist = [1,2,3]\nhd(list)\ntl(list)\n```\n\n[11, 12, 13] will print as \"char list\", '\\v\\f\\r', single quotes are char lists, double quotes are strings.\n\n##### Tuples\n\nCurly brackets, can hold any value, like lists.\n\n{1, true, :ok}\n\nTuples store elements contiguously in memory. Accessing by index is a fast operation.\nElixir data types are immutable.\n\nString concatentation is done with the `\u003c\u003e` operator\n\n##### Operators\n\nHas double equals and triple equals. 1 == 1.0 #=\u003e true vs. 1 === 1.0 #=\u003e false\n\n1 \u003c :atom works because datatypes have a sort order, and so sorting algorithms don't have to worry about types.\n\nThe match operator (`=`)\n\n```\nx=1\n1=x\n```\n\n2=x does not match, a MatchError is raised.\n\nPattern matching on tuples. Count and type needs to match.\n`{a, b, c} = {:hello, \"world\", 42}`\n\n##### Pin operator\n\nUse pin operator when you want to match against existing variable's value rather than rebinding the variable.\n\ne.g. ^x when you want to preserve current value\n\n`cond` is similar to if else statements in other languages\n\n```\ncond do\n  condition -\u003e\n  condition -\u003e\n\nend\n```\n\nif and unless\n\n\"keyword list\" syntax style\n\n`if true, do: 1 + 2`\n\n### Binaries, strings, and char lists\n\nGet a character's code point by using `?char` e.g. `?a` in iex\n\nDefine a binary like this: `\u003c\u003c1,2,3\u003e\u003e`. A binary is a sequence of bytes.\nA char list is a list of code points.\n\n##### Keyword lists and maps\n\nWhen we have a 2-item tuples, and first item is an atom, we call it a \"keyword list\", e.g.\n\n`list = [{:a, 1}, {:b, 2}]`\n\n* keys must be atoms\n* keys are ordered, as specified by developer\n* keys can be given more than once\n\nMaps\n\n * allow any value as a key\n * maps keys do not follow any ordering\n\ne.g. `%{:a =\u003e 1, 2 =\u003e :b}\n\nWhen a map is used in a pattern, it will always match on a subset of the given value.\n\n`put_in/2` and `update_in/2` macros, `get_and_update_in/2` (extract value and update data)\n\n##### Modules\n\n```\ndefmodule Math do\n  def sum(a, b) do\n    a + b\n  end\nend\n```\n\nMath.sum(1,2)\n\n##### Function capturing\n\nRetrieve functions as a function using the name/arity style\n\nCapture syntax can be used as shorthand for creating functions.\ne.g. `fun = \u0026(\u00261 + 1)`\n`\u0026(\u00261+1)` is same as `fn x -\u003e x + 1 end`\n\n\u00261 represents first argument\n\nDefault arguments are supported. Weird thing about function without body, when there are multiple clauses.\n\n##### Recursion\n\nLoops are different in a functional language compared with an imperative language\nA function may have multiple clauses. The function matches that matches the args passed to it.\n\n##### Ranges\n\nRanges are supported, e.g. `1..3`\n\nFunctions in the Enum module are \"eager\", each operation generates an intermiedate list until we reach the result.\n\n`|\u003e` pipe operator\n\n`1..10_000 |\u003e Enum.map(\u0026(\u00261 * 3)) |\u003e Enum.sum`\n\n##### Streams\n\nStreams support lazy operations. \"Streams are lazy composable enumerables\". Does not generate intermediate list. Invoked when we pass the underlying stream to the Enum module.\n\nFor large, or possible infinite collections.\n\n```\nstream = Stream.cycle([1,2,3])\nEnum.take(stream, 10)\n```\n\nStream.resource/3\n\n##### Processes\n\nNot OS processes. Not like threads. They are lightweight in terms of memory and CPU. Can have 10s or even 100s of thousands of processes running simultaneously.\n\n`iex\u003e pid = spawn fn -\u003e 1 + 2 end`\n\n`Process.alive?(pid)`\n\nSend and receive messages between processes, send/2 and receive/1\n\n##### Links\n\nProcess.link/1\n\nspawn/1 and spawn_link/1 We link our processes to supervisors, which restart processes. Processes are isolated.\n\n##### Tasks\n\nTask.start/1\nTask.start_link/1\n\nUse Task to get better error reports\n\n##### State\n\nUsing processes to maintain state and name registration are very common patterns\n\nElixir provides an abstraction layer called an \"Agent\" around state\n\n`GenServer` for building generic servers\n\n##### File I/O\n\n`File` module\n\nFile.read/1, vs. File.read!/1 (latter returns contents of file instead of tuple, raises an error)\nWithout bang is preferred when handling different outcomes\n\n```\ncase File.read(file) do\n  {:ok, body}      -\u003e # do something with the `body`\n  {:error, reason} -\u003e # handle the error caused by `reason`\nend\n```\n\nBang variation is good for handing errors\n\nProcesses and group leaders\n\nWriting to stdio, actually sending message to group leader\n`Process.group_leader`\n\niodata and chardata\n\nalias, require and import (\"directives\", because they have lexical scope) Lexical scope means it may only be executed within the block where it is defined.\n\n```\niex\u003e import List, only: [duplicate: 2]\nList\n```\n\nModule nesting\nModule attributes\n\n  1. annotate the module\n  2. hey work as constants\n  3. hey work as temporary module storage to be used during compilation\n\n\n@moduledoc\n\nModule attributes as constants, e.g. initial state\n\n```\ndefmodule MyServer do\n  @initial_state %{host: \"147.0.0.1\", port: 3456}\n  IO.inspect @initial_state\nend\n```\n\nAs temporary storage (module attribute values read at compilation time not runtime)\n\n##### Structs\n\n```\ndefmodule User do\n  defstruct name: \"John\", age: 25\nend\n\n%User{}\n%User{age: 25, name: \"Bill\"}\njohn=%User{age: 25}\nbill=%User{john | age: 30}\n```\n\nStructs are bare maps underneath\n\n@enforce_keys to enforce certain keys are set\n\n##### Protocols\n\nMechanism to achieve polymorphism\n\n`defprotocol` and `defimpl`\n\nDeriving, use implementation for `Any`\n\ne.g. Derive the Size protocol, using the Any implementation\n@derize [Size]\n\n@fallback_to_any true\n\n##### Built-in protocols\n\nEnum, String.Chars (to_string), Inspect\nProtocol consolidation\n\n##### Comprehensions\n\n* loop, filter, map into another list\n* three parts: generators, filters, collectables\n\nPattern matching on the generator (left hand) side\nOnly pick up the \"good\" values\n\n```\niex\u003e values = [good: 1, good: 2, bad: 3, good: 4]\niex\u003e for {:good, n} \u003c- values, do: n * n\n[1, 4, 16]\n```\n\n##### Sigils\n\nWorking with textual representations\n\n`~r` create regular expressions\n\n`iex\u003e h sigil_r`\n\n`~s` similar to creating double quoted strings, useful when string contains double quotes\n\n`~w` (word list) e.g. ~w(foo bar baz)\n\nAlso support heredocs\n\n##### try, catch, rescue\n\ntry and `after`, after runs whether try was successful or not\n\n##### Types and specs\n\nDynamically typed, though comes with typespecs, which:\n\n  * declare typed function signatures\n  * declare custom data types\n\n\n@type directive allows us to create our own type\nWe can use this type in the typespec\nCan perform static code analysis using the type information\n\n##### Behaviours\n\nKind of like an interface, a set of function signatures a module has to implement\n\n\n##### Erlang libraries\n\nFormatted text output, `:io.format/2`\ncrypto module\ndigraph (directed graphs) module\nErlang Term Storage, `ets` and `dets`\nmath module\nqueue module, double-ended FIFO\nrand module\nzip and zlib\n\n##### First project\n\n`mix.exs` file has project configuration\n\n`mix compile`\n\nTest files are elixir script files (no compilation necessary)\n\n`mix test`\n\nMix supports environments:\n\n```\n:dev, :test, :prod\n```\n\n`mix help`\n\n##### Agent\n\nCan review processes section from getting started\n\nElixir is immutable where nothing is shared by default. To provide state, two main options:\n\n  * Processes\n  * ETS (Erlang Term Storage)\n\nAgent (simple wrapper around state)\nGenServer (generic servers, \"processes\"), sync and async, code reloading\nGenEvent (generic event, \"managers\")\nTask - async units of computation, spawn process, retrieve results later\n\nAll implemented on top of processes\n\n##### GenServer\n\nA genserver is implemented in two parts: the client API and the server callbacks\n\nTwo types of calls for genserver: calls and casts\n\nCalls are synchronous, server must respond\n\nCasts are async\n\nWhen should we use monitors, and when should we use links?\n\nLinks are bi-directional (both sides crash). Monitor is uni-directional. Use monitors when you want to be informed of crashes, but not crash.\n\n##### Supervisors\n\n\"Let it crash\" - supervisor will start a fresh copy of the registry\n\n`iex -S mix` vs. `iex -S mix run --no-start` to not start applications\n\nMix makes a distinction between projects and applications\n\nDefines a new supervisor with a `:simple_one_for_one` strategy\nNo workers are started during the supervisor initialization\nA new worker is started each time start_child/2 is started\n\n\"Supervision trees\" - supervisors that supervise other supervisors\n\nStart processes inside supervision trees so they are introspectable. Can use tools like Observer to introspect on them.\n\n##### ETS\n\nErlang term storage - can be used as a cache\nDon't use prematurely\n\ncall is sync\ncast is async\n\nQuestions: is there a debugger?\nHow to do basic logging?\n\n##### Dependencies\n\nWe use the Hex package manager\nPlug is an HTTP API\n\nMix generates a Mix.lock file for repeatable builds\n`mix deps.get`\n\nFor internal dependencies, can either use a git repo, or umbrella project.\n\n##### TCP echo server\n\n1. listens to port until available, and holds a socket\n2. wait for client connection on that port and accepts it\n3. read the client request and write a response back\n\nFirst version, client connection (via telnet) and server crashes when telnet session ends\nThen we set up a Task to run the server again\n\nNext we need a Task supervisor so we can support multiple client connections\n\nOne process is an acceptor that spawns other processes to serve requests\n\n##### doctests\n\nIndent examples, have specific requirements\n\nRun server with `mix run --no-halt`\n\nUse `with` to combine matching clauses\nhttps://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1\n\n:capture_log\n\n##### Routing\n\nRouting table for distributed application\n\ne.g.\n\n```\n[{?a..?m, :\"foo@computer-name\"},\n {?n..?z, :\"bar@computer-name\"}]\n```\n\nNodes need `~/.erlang.cookie` and empd needs to be running\n\nNeed to start the VM with a name\n\niex --sname foo\n\nCan use `Node.spawn_link`\nCan use rpc: `:rpc.call(:\"foo@Andrews-MacBook-Pro\", Hello, :world, [])`\nCan use GenServer call\nCould use Tasks\n\nasync/await - async run code, get result later on\n\nDistributed tasks\n\n##### Hello World\n\nhttp://technotif.com/building-website-phoenix-framework/\nRun server\n`iex -S mix phoenix.server`\nlocalhost:4000\n\n\n##### Blog\n\n`mix phoenix.new blog`\n\n`mix ecto.migrate`\n\n`mix phoenix.server`\n\n`mix phoenix.routes`\n\n`iex -S mix phoenix.server` and navigate to `/posts`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyatkinson%2Felixir-getting-started","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandyatkinson%2Felixir-getting-started","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandyatkinson%2Felixir-getting-started/lists"}