{"owner":"elixir-lang","repo":"elixir","hasSkills":true,"totalSkillsCount":11,"totalTokensCount":34855,"categories":["anthropic-skill","cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":["lib/elixir/pages/references/library-guidelines.md","lib/elixir/pages/references/sbom.md","lib/elixir/pages/references/naming-conventions.md","lib/elixir/pages/references/operators.md","lib/elixir/pages/references/patterns-and-guards.md","lib/elixir/pages/references/gradual-set-theoretic-types.md","lib/elixir/pages/references/compatibility-and-deprecations.md","lib/elixir/pages/references/unicode-syntax.md","lib/elixir/pages/references/syntax-reference.md","lib/elixir/pages/references/typespecs.md",".cursorrules (elixir-engineer-guidelines-cursorrules-prompt-file.mdc)"],"skills":{"lib/elixir/pages/references/library-guidelines.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Library guidelines\n\nThis document outlines general guidelines for those writing and publishing\nElixir libraries meant to be consumed by other developers.\n\n## Getting started\n\nYou can create a new Elixir library by running the `mix new` command:\n\n    $ mix new my_library\n\nThe project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.\n\nEvery project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.\n\nThe `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).\n\n## Publishing\n\nWriting code is only the first of many steps to publish a package. We strongly recommend developers to:\n\n  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).\n\n  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.\n\n  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.\n\n  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.\n\n  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports \"extra pages\", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.\n\n  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.\n\nProjects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).\n\n## Dependency handling\n\nWhen your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.\n\nKeep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).\n\nOn the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.\n\nIf you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.\n\n### Dependency Version Requirements\n\nWhen depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `\"~> x.y\"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.\n\nThe exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `\"~> 0.1.2\"` is a better default.\n\nA common mistake is to use a dependency in the format of `\"~> x.y.z\"` to express \"a version greater than `x.y.z`\". For example, if you are depending on `\"~> 1.2\"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `\"~> 1.2.1\"` to express that dependency, you are preventing users from upgrading to `\"1.3.0\"` or higher! Instead of `\"~> 1.2.1\"`, you should use `\"~> 1.2 and >= 1.2.1\"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.\n","lib/elixir/pages/references/sbom.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Software Bill of Materials\n\nA Software Bill of Materials (SBoM) is a structured inventory of the components that make up a software system. This guide explains what SBoMs are, why they matter, and how to generate them for Elixir projects.\n\n## What is an SBoM?\n\nAn SBoM is a formal, machine-readable record of all components in a piece of software. Think of it as a detailed ingredient list for your application. A typical SBoM includes:\n\n  * **Dependencies**: all libraries and packages your project uses\n  * **Versions**: the exact version of each component\n  * **Source locations**: where each component was obtained (Hex, GitHub, etc.)\n  * **Checksums**: cryptographic hashes to verify integrity\n  * **Licensing information**: the license under which each component is distributed\n\nTwo widely adopted standards exist for SBoM formats:\n\n  * [CycloneDX](https://cyclonedx.org/): a lightweight standard designed for security contexts\n  * [SPDX](https://spdx.dev/): a more comprehensive standard originally focused on licensing\n\nBoth formats are machine-readable (JSON, XML) and designed to be consumed by automated tooling.\n\n> #### SBoM is an inventory, not a certification {: .info}\n>\n> An SBoM does not claim that software is secure, compliant, or free of vulnerabilities.\n> It simply provides a detailed inventory that enables further analysis. Security and\n> compliance assessments are performed by separate tools that consume the SBoM.\n\n## Why generate SBoMs?\n\nThere are three main reasons to generate SBoMs for your projects.\n\n### Vulnerability analysis\n\nWhen a security vulnerability (CVE) is discovered in a library, you need to quickly determine if your projects are affected. SBoMs make this possible by providing a complete inventory of your dependencies.\n\nTools like [OWASP Dependency-Track](https://dependencytrack.org/) continuously monitor your SBoMs against vulnerability databases. When a new CVE is published, you get notified if any of your projects use the affected component.\n\nWithout an SBoM, answering \"are we affected by CVE-2024-XXXXX?\" means manually checking each project, which is time-consuming and error-prone.\n\n### Regulatory requirements\n\nSBoMs are required by some regulations and procurement policies:\n\n  * **US Executive Order 14028** (2021) requires SBoMs for certain software supplied to the U.S. federal government, particularly for designated critical software\n  * **EU Cyber Resilience Act** introduces requirements for component inventories (commonly fulfilled using SBoMs) for products with digital elements placed on the EU market\n  * **Safety-critical industries** (medical devices, automotive, aerospace) often require detailed component inventories as part of certification\n\nCustomers and partners may also request SBoMs as part of their own compliance efforts.\n\n### License compliance\n\nEvery dependency in your project comes with a license. An SBoM provides a starting point for license review by listing the declared license for each package. This helps you:\n\n  * Get an overview of licenses in your dependency tree\n  * Flag packages that may need closer review\n  * Support due diligence for acquisitions, audits, or legal review\n\nNote that package-level license information (as provided by mix_sbom) reflects what the package declares, not necessarily all licenses present in its source files. For thorough license compliance, file-level scanning tools like ORT provide deeper analysis.\n\n## Generating SBoMs with mix_sbom\n\n[mix_sbom](https://github.com/erlef/mix_sbom) is an EEF project that generates CycloneDX SBoMs for Elixir projects.\n\n### Installation\n\nThere are several ways to install mix_sbom:\n\n  * **As a project dependency**: add `sbom` to your `mix.exs`\n  * **As a global escript**: run `mix escript.install hex sbom` (requires Elixir 1.19.4+)\n  * **As a standalone binary**: download from the [releases page](https://github.com/erlef/mix_sbom/releases)\n\nThe standalone binary is useful for CI environments or when you don't want to modify your project's dependencies. It requires no local Elixir or Erlang installation.\n\n### Basic usage\n\nTo generate an SBoM for your project using the standalone binary:\n\n```console\n$ mix_sbom cyclonedx /path/to/your/project\n```\n\nThis creates a `bom.cdx.json` file in CycloneDX format containing your project's complete dependency tree.\n\n### Common options\n\nThe most useful options are:\n\n  * `-o, --output PATH`: specify the output file (default: `bom.cdx.json`)\n  * `-t, --format FORMAT`: output format (`json`, `xml`, or `protobuf`)\n  * `-s, --schema VERSION`: CycloneDX schema version\n\nFor example, to generate an XML format SBoM:\n\n```console\n$ mix_sbom cyclonedx --format xml --output sbom.xml /path/to/project\n```\n\n## CI integration\n\nFor automated SBoM generation, mix_sbom provides a GitHub Action:\n\n```yaml\nname: Generate SBoM\non:\n  release:\n    types: [published]\n\njobs:\n  sbom:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: erlef/mix_sbom@v0\n        with:\n          path: \".\"\n          format: \"json\"\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sbom\n          path: bom.cdx.json\n```\n\nThis workflow generates an SBoM whenever you publish a release and uploads it as a build artifact. See the [action's documentation](https://github.com/erlef/mix_sbom) for additional options.\n\n## Deeper analysis with ORT\n\nmix_sbom provides package-level license information based on what each dependency declares. However, some compliance workflows require file-level scanning. A package might declare an MIT license but contain individual files under different licenses, or include vendored code with its own licensing terms.\n\nThe [OSS Review Toolkit (ORT)](https://oss-review-toolkit.org/) addresses this by scanning actual source files for license headers and copyright notices. ORT supports Mix projects and provides:\n\n  * **File-level license detection**: scans source code for license texts and SPDX identifiers\n  * **Copyright holder identification**: extracts copyright notices from files\n  * **Policy enforcement**: define rules for allowed and denied licenses\n  * **Multi-ecosystem support**: analyze projects that span multiple package managers\n\nFor organizations with strict compliance requirements, ORT complements mix_sbom by providing the deeper analysis needed for thorough license audits.\n\nSee the [ORT Mix plugin documentation](https://oss-review-toolkit.org/ort/docs/plugins/package-managers/Mix) for details.\n\n## Next steps\n\n  * [CycloneDX Specification](https://cyclonedx.org/specification/overview/): learn more about the SBoM format\n  * [OWASP Dependency-Track](https://dependencytrack.org/): continuous SBoM analysis platform\n  * [mix_sbom documentation](https://sbom.hexdocs.pm): full documentation and advanced options\n","lib/elixir/pages/references/naming-conventions.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Naming conventions\n\nThis document is a reference of the naming conventions in Elixir, from casing to punctuation characters.\n\nThe naming convention is, by definition, a subset of the Elixir syntax. A convention aims to\nfollow and set best practices for language and the community. If instead you want a complete reference into the Elixir syntax, beyond its conventions, see [the Syntax reference](syntax-reference.md).\n\n## Casing\n\nElixir developers must use `snake_case` when defining variables, function names, module attributes, and the like:\n\n    some_map = %{this_is_a_key: \"and a value\"}\n    is_map(some_map)\n\nAliases, commonly used as module names, are an exception as they must be capitalized and written in `CamelCase`, like `OptionParser`. For aliases, capital letters are kept in acronyms, like `ExUnit.CaptureIO` or `Mix.SCM`.\n\nAtoms can be written either in `:snake_case` or `:CamelCase`, although the convention is to use the snake case version throughout Elixir.\n\nGenerally speaking, filenames follow the `snake_case` convention of the module they define. For example, `MyApp` should be defined inside the `my_app.ex` file. However, this is only a convention. At the end of the day any filename can be used as they do not affect the compiled code in any way.\n\n## Underscore (`_foo`)\n\nElixir relies on underscores in different situations.\n\nFor example, a value that is not meant to be used must be assigned to `_` or to a variable starting with underscore:\n\n    iex> {:ok, _contents} = File.read(\"README.md\")\n\nFunction names may also start with an underscore. Such functions are never imported by default:\n\n    iex> defmodule Example do\n    ...>   def _wont_be_imported do\n    ...>     :oops\n    ...>   end\n    ...> end\n\n    iex> import Example\n    iex> _wont_be_imported()\n    ** (CompileError) iex:1: undefined function _wont_be_imported/0\n\nDue to this property, Elixir relies on functions starting with underscore to attach compile-time metadata to modules. Such functions are most often in the `__foo__` format. For example, every module in Elixir has an [`__info__/1`](`c:Module.__info__/1`) function:\n\n    iex> String.__info__(:functions)\n    [at: 2, capitalize: 1, chunk: 2, ...]\n\nElixir also includes five special forms that follow the double underscore format: `__CALLER__/0`, `__DIR__/0`, `__ENV__/0`and `__MODULE__/0` retrieve compile-time information about the current environment, while `__STACKTRACE__/0` retrieves the stacktrace for the current exception.\n\n## Trailing bang (`foo!`)\n\nA trailing bang (exclamation mark) signifies a function or macro where failure cases raise an exception. They most often exist as a \"raising variant\" of a function that returns `:ok`/`:error` tuples (or `nil`).\n\nOne example is `File.read/1` and `File.read!/1`. `File.read/1` will return a success or failure tuple, whereas `File.read!/1` will return a plain value or else raise an exception:\n\n    iex> File.read(\"file.txt\")\n    {:ok, \"file contents\"}\n    iex> File.read(\"no_such_file.txt\")\n    {:error, :enoent}\n\n    iex> File.read!(\"file.txt\")\n    \"file contents\"\n    iex> File.read!(\"no_such_file.txt\")\n    ** (File.Error) could not read file no_such_file.txt: no such file or directory\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n    case File.read(file) do\n      {:ok, body} -> # do something with the `body`\n      {:error, reason} -> # handle the error caused by `reason`\n    end\n\nHowever, if you expect the outcome to always be successful (for instance, if you expect the file always to exist), the bang variation can be more convenient and will raise a more helpful error message (than a failed pattern match) on failure.\n\nWhen thinking about failure cases, we are often thinking about semantic errors related to the operation being performed, such as failing to open a file or trying to fetch key from a map. Errors that come from invalid argument types, or similar, must always raise regardless if the function has a bang or not. In such cases, the exception is often an `ArgumentError` or a detailed `FunctionClauseError`:\n\n    iex(1)> File.read(123)\n    ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1\n\n        The following arguments were given to IO.chardata_to_string/1:\n\n            # 1\n            123\n\n        Attempted function clauses (showing 2 out of 2):\n\n            def chardata_to_string(string) when is_binary(string)\n            def chardata_to_string(list) when is_list(list)\n\nMore examples of paired functions: `Base.decode16/2` and `Base.decode16!/2`, `File.cwd/0` and `File.cwd!/0`. In some situations, you may have bang functions without a non-bang counterpart. They also imply the possibility of errors, such as: `Protocol.assert_protocol!/1` and `PartitionSupervisor.resize!/2`. This can be useful if you foresee the possibility of adding a non-raising variant in the future.\n\n## Trailing question mark (`foo?`)\n\nFunctions that return a boolean are named with a trailing question mark.\n\nExamples: `Keyword.keyword?/1`, `Mix.debug?/0`, `String.contains?/2`\n\nHowever, functions that return booleans and are valid in guards follow another convention, described next.\n\n## `is_` prefix (`is_foo`)\n\nType checks and other boolean checks that are allowed in guard clauses are named with an `is_` prefix.\n\nExamples: `Integer.is_even/1`, `is_list/1`\n\nThese 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. Type checks that are not valid in guard clauses do not follow this convention, such as `Keyword.keyword?/1`.\n\nA trailing question mark should not be used in combination with the `is_` prefix.\n\n## Special names\n\nSome names have specific meaning in Elixir. We detail those cases below.\n\n### length and size\n\nWhen you see `size` in a function name, it means the operation runs in constant time (also written as \"O(1) time\") because the size is stored alongside the data structure.\n\nExamples: `map_size/1`, `tuple_size/1`\n\nWhen you see `length`, the operation runs in linear time (\"O(n) time\") because the entire data structure has to be traversed.\n\nExamples: `length/1`, `String.length/1`\n\nIn other words, functions using the word \"size\" in its name will take the same amount of time whether the data structure is tiny or huge. Conversely, functions having \"length\" in its name will take more time as the data structure grows in size.\n\n### get, fetch, fetch!\n\nWhen you see the functions `get`, `fetch`, and `fetch!` for key-value data structures, you can expect the following behaviours:\n\n  * `get` returns a default value (which itself defaults to `nil`) if the key is not present, or returns the requested value.\n  * `fetch` returns `:error` if the key is not present, or returns `{:ok, value}` if it is.\n  * `fetch!` *raises* if the key is not present, or returns the requested value.\n\nExamples: `Map.get/2`, `Map.fetch/2`, `Map.fetch!/2`, `Keyword.get/2`, `Keyword.fetch/2`, `Keyword.fetch!/2`\n\n### compare\n\nThe function `compare/2` should return `:lt` if the first term is less than the second, `:eq` if the two\nterms compare as equivalent, or `:gt` if the first term is greater than the second.\n\nExamples: `DateTime.compare/2`\n\nNote that this specific convention is important due to the expectations of `Enum.sort/2`\n","lib/elixir/pages/references/operators.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Operators reference\n\nThis document is a complete reference of operators in Elixir, how they are parsed, how they can be defined, and how they can be overridden.\n\n## General operators\n\nElixir provides the following built-in operators:\n\n  * [`+`](`+/1`) and [`-`](`-/1`) - unary positive/negative\n  * [`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), and [`/`](`//2`) - basic arithmetic operations\n  * [`++`](`++/2`) and [`--`](`--/2`) - list concatenation and subtraction\n  * [`and`](`and/2`) and [`&&`](`&&/2`) - strict and relaxed boolean \"and\"\n  * [`or`](`or/2`) and [`||`](`||/2`) - strict and relaxed boolean \"or\"\n  * [`not`](`not/1`) and [`!`](`!/1`) - strict and relaxed boolean \"not\"\n  * [`in`](`in/2`) and [`not in`](`in/2`) - membership\n  * [`@`](`@/1`) - module attribute\n  * [`..`](`../0`), [`..`](`../2`), and [`..//`](`..///3`) - range creation\n  * [`<>`](`<>/2`) - binary concatenation\n  * [`|>`](`|>/2`) - pipeline\n  * [`=~`](`=~/2`) - text-based match\n\nMany of those can be used in guards. Consult the [list of allowed guard functions and operators](patterns-and-guards.md#list-of-allowed-functions-and-operators).\n\nAdditionally, there are a few other operators that Elixir parses but doesn't actually use.\nSee [Custom and overridden operators](#custom-and-overridden-operators) below for a list and for guidelines about their use.\n\nSome other operators are special forms and cannot be overridden:\n\n  * [`^`](`^/1`) - pin operator\n  * [`.`](`./2`) - dot operator\n  * [`=`](`=/2`) - match operator\n  * [`&`](`&/1`) - capture operator\n  * [`::`](`::/2`) - type operator\n\nFinally, these operators appear in the precedence table below but are only meaningful within certain constructs:\n\n  * `=>` - see [`%{}`](`%{}/1`)\n  * `when` - see [Guards](patterns-and-guards.md#guards)\n  * `<-` - see [`for`](`for/1`) and [`with`](`with/1`)\n  * `\\\\` - see [Default arguments](`Kernel#def/2-default-arguments`)\n\n## Comparison operators\n\nElixir provides the following built-in comparison operators (all of which can be used in guards):\n\n  * [`==`](`==/2`) - equal to\n  * [`===`](`===/2`) - strictly equal to\n  * [`!=`](`!=/2`) - not equal to\n  * [`!==`](`!==/2`) - strictly not equal to\n  * [`<`](`</2`) - less-than\n  * [`>`](`>/2`) - greater-than\n  * [`<=`](`<=/2`) - less-than or equal to\n  * [`>=`](`>=/2`) - greater-than or equal to\n\nThe only difference between [`==`](`==/2`) and [`===`](`===/2`) is that [`===`](`===/2`) is strict when it comes to comparing integers and floats:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 === 1.0\nfalse\n```\n\n[`!=`](`!=/2`) and [`!==`](`!==/2`) act as the negation of [`==`](`==/2`) and [`===`](`===/2`), respectively.\n\n## Operator precedence and associativity\n\nThe following is a list of all operators that Elixir is capable of parsing, ordered from higher to lower precedence, alongside their associativity:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`@`                                            | Unary\n`.`                                            | Left\n`+` `-` `!` `^` `not`                          | Unary\n`**`                                           | Left\n`*` `/`                                        | Left\n`+` `-`                                        | Left\n`++` `--` `+++` `---` `..` `<>`                | Right\n`//` (valid only inside `..//`)                | Right\n`in` `not in`                                  | Left\n`\\|>` `<<<` `>>>` `<<~` `~>>` `<~` `~>` `<~>`  | Left\n`<` `>` `<=` `>=`                              | Left\n`==` `!=` `=~` `===` `!==`                     | Left\n`&&` `&&&` `and`                               | Left\n`\\|\\|` `\\|\\|\\|` `or`                           | Left\n`=`                                            | Right\n`&`, `...`                                     | Unary\n`\\|`                                           | Right\n`::`                                           | Right\n`when`                                         | Right\n`<-` `\\\\`                                      | Left\n`=>` (valid only inside `%{}`)                 | None\n\nElixir also has two ternary operators:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`first..last//step`                            | Right\n`%{map \\| key => value, ...}`                  | None\n\n> #### Deprecated operator precedence {: .info}\n>\n> Elixir parses `not left in right` as `not(left in right)` and `!left in right` as `!(left in right)`, which mismatches the precedence table above, but such behaviour is deprecated and emits a warning. Both constructs must be written as `left not in right` instead. In future major versions, the parser will match the table above.\n\n## Custom and overridden operators\n\nElixir is capable of parsing a predefined set of operators. It's not possible to define new operators (as supported by some languages). However, not all operators that Elixir can parse are *used* by Elixir: for example, `+` and `||` are used by Elixir for addition and boolean *or*, but `<~>` is not used (but valid).\n\nTo define an operator, you can use the usual `def*` constructs (`def`, `defp`, `defmacro`, and so on) but with a syntax similar to how the operator is used:\n\n```elixir\ndefmodule MyOperators do\n  # We define ~> to return the maximum of the given two numbers,\n  # and <~ to return the minimum.\n\n  def a ~> b, do: max(a, b)\n  def a <~ b, do: min(a, b)\nend\n```\n\nTo use the newly defined operators, you **have to** import the module that defines them:\n\n```elixir\niex> import MyOperators\niex> 1 ~> 2\n2\niex> 1 <~ 2\n1\n```\n\nThe following is a table of all the operators that Elixir is capable of parsing, but that are not used by default:\n\n  * `|||`\n  * `&&&`\n  * `<<<`\n  * `>>>`\n  * `<<~`\n  * `~>>`\n  * `<~`\n  * `~>`\n  * `<~>`\n  * `+++`\n  * `---`\n  * `...`\n\nThe following operators are used by the `Bitwise` module when imported: [`&&&`](`Bitwise.&&&/2`), [`<<<`](`Bitwise.<<</2`), [`>>>`](`Bitwise.>>>/2`), and [`|||`](`Bitwise.|||/2`). See the `Bitwise` documentation for more information.\n\nNote that the Elixir community generally discourages custom operators. They can be hard to read and even more to understand, as they don't have a descriptive name like functions do. That said, some specific cases or custom domain specific languages (DSLs) may justify these practices.\n\nIt is also possible to replace predefined operators, such as `+`, but doing so is extremely discouraged.\n","lib/elixir/pages/references/patterns-and-guards.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Patterns and guards\n\nElixir provides pattern matching, which allows us to assert on the shape or extract values from data structures. Patterns are often augmented with guards, which give developers the ability to perform more complex checks, albeit limited.\n\nThis document provides a complete reference on patterns and guards, their semantics, where they are allowed, and how to extend them.\n\n## Patterns\n\nPatterns in Elixir are made of variables, literals, and data structure specific syntax. One of the most used constructs to perform pattern matching is the match operator ([`=`](`=/2`)):\n\n```iex\niex> x = 1\n1\niex> 1 = x\n1\n```\n\nIn the example above, `x` starts without a value and has `1` assigned to it. Then, we compare the value of `x` to the literal `1`, which succeeds as they are both `1`.\n\nMatching `x` against 2 would raise:\n\n```iex\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nPatterns are not bidirectional. If you have a variable `y` that was never assigned to (often called an unbound variable) and you write `1 = y`, an error will be raised:\n\n```iex\niex> 1 = y\n** (CompileError) iex:2: undefined variable \"y\"\n```\n\nIn other words, patterns are allowed only on the left side of `=`. The right side of `=` follows the regular evaluation semantics of the language.\n\nNow let's cover the pattern matching rules for each construct and then for each relevant data types.\n\n### Variables\n\nVariables in patterns are always assigned to:\n\n```iex\niex> x = 1\n1\niex> x = 2\n2\niex> x\n2\n```\n\nIn other words, Elixir supports rebinding. In case you don't want the value of a variable to change, you can use the pin operator (`^`):\n\n```iex\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nIf the same variable appears multiple times in the same pattern, then all of them must be bound to the same value:\n\n```iex\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nHowever, a variable cannot be defined through itself in the same pattern. This includes cases where the variable appears on both sides of a nested match operator:\n\n```elixir\n{:ok, x} = {x, :ok}\n%{a: value} = %{b: value}\n```\n\nSuch patterns are rejected as cyclic variable definitions. You can rewrite them by matching once and then using guards or separate comparisons for the additional constraints.\n\nThe underscore variable (`_`) has a special meaning as it can never be bound to any value. It is especially useful when you don't care about certain value in a pattern:\n\n```iex\niex> {_, integer} = {:not_important, 1}\n{:not_important, 1}\niex> integer\n1\niex> _\n** (CompileError) iex:3: invalid use of _\n```\n\nA pinned value represents the value itself and not its – even if syntactically equal – pattern. The right hand side is compared to be equal to the pinned value:\n\n```iex\niex> x = %{}\n%{}\niex> {:ok, %{}} = {:ok, %{a: 13}}\n{:ok, %{a: 13}}\niex> {:ok, ^x} = {:ok, %{a: 13}}\n** (MatchError) no match of right hand side value: {:ok, %{a: 13}}\n    (stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6\n    iex:2: (file)\n```\n\n### Literals (numbers and atoms)\n\nAtoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:\n\n```iex\niex> :atom = :atom\n:atom\niex> :atom = :another_atom\n** (MatchError) no match of right hand side value: :another_atom\n```\n\nSimilar rule applies to numbers. Finally, note that numbers in patterns perform strict comparison. In other words, integers to do not match floats:\n\n```iex\niex> 1 = 1.0\n** (MatchError) no match of right hand side value: 1.0\n```\n\n### Tuples\n\nTuples may appear in patterns using the curly brackets syntax (`{}`). A tuple in a pattern will match only tuples of the same size, where each individual tuple element must also match:\n\n```iex\niex> {:ok, integer} = {:ok, 13}\n{:ok, 13}\n\n# won't match due to different size\niex> {:ok, integer} = {:ok, 11, 13}\n** (MatchError) no match of right hand side value: {:ok, 11, 13}\n\n# won't match due to mismatch on first element\niex> {:ok, binary} = {:error, :enoent}\n** (MatchError) no match of right hand side value: {:error, :enoent}\n```\n\n### Lists\n\nLists may appear in patterns using the square brackets syntax (`[]`). A list in a pattern will match only lists of the same size, where each individual list element must also match:\n\n```iex\niex> [:ok, integer] = [:ok, 13]\n[:ok, 13]\n\n# won't match due to different size\niex> [:ok, integer] = [:ok, 11, 13]\n** (MatchError) no match of right hand side value: [:ok, 11, 13]\n\n# won't match due to mismatch on first element\niex> [:ok, binary] = [:error, :enoent]\n** (MatchError) no match of right hand side value: [:error, :enoent]\n```\n\nOpposite to tuples, lists also allow matching on non-empty lists by using the `[head | tail]` notation, which matches on the `head` and `tail` of a list:\n\n```iex\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nMultiple elements may prefix the `| tail` construct:\n\n```iex\niex> [first, second | tail] = [1, 2, 3]\n[1, 2, 3]\niex> tail\n[3]\n```\n\nNote `[head | tail]` does not match empty lists:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nGiven charlists are represented as a list of integers, one can also perform prefix matches on charlists using the list concatenation operator ([`++`](`++/2`)):\n\n```elixir\niex> ~c\"hello \" ++ world = ~c\"hello world\"\n~c\"hello world\"\niex> world\n~c\"world\"\n```\n\nWhich is equivalent to matching on `[?h, ?e, ?l, ?l, ?o, ?\\s | world]`. Suffix matches (`hello ++ ~c\" world\"`) are not valid patterns.\n\n### Maps\n\nMaps may appear in patterns using the percentage sign followed by the curly brackets syntax (`%{}`). Opposite to lists and tuples, maps perform a subset match. This means a map pattern will match any other map that has at least all of the keys in the pattern.\n\nHere is an example where all keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\"}\n%{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nHere is when a subset of the keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\", age: 23}\n%{age: 23, name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf a key in the pattern is not available in the map, then they won't match:\n\n```iex\niex> %{name: name, age: age} = %{name: \"meg\"}\n** (MatchError) no match of right hand side value: %{name: \"meg\"}\n```\n\nNote that the empty map will match all maps, which is a contrast to tuples and lists, where an empty tuple or an empty list will only match empty tuples and empty lists respectively:\n\n```iex\niex> %{} = %{name: \"meg\"}\n%{name: \"meg\"}\n```\n\nFinally, note map keys in patterns must always be literals or previously bound variables matched with the pin operator.\n\n### Structs\n\nStructs may appear in patterns using the percentage sign, the struct module name or a variable followed by the curly brackets syntax (`%{}`).\n\nGiven the following struct:\n\n```elixir\ndefmodule User do\n  defstruct [:name]\nend\n```\n\nHere is an example where all keys match:\n\n```iex\niex> %User{name: name} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf an unknown key is given, the compiler will raise an error:\n\n```iex\niex> %User{type: type} = %User{name: \"meg\"}\n** (CompileError) iex: unknown key :type for struct User\n```\n\nThe struct name can be extracted when putting a variable instead of a module name:\n\n```elixir\niex> %struct_name{} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> struct_name\nUser\n```\n\n### Binaries\n\nBinaries may appear in patterns using the double less-than/greater-than syntax ([`<<>>`](`<<>>/1`)). A binary in a pattern can match multiple segments at the same time, each with different type, size, and unit:\n\n```iex\niex> <<val::unit(8)-size(2)-integer>> = <<123, 56>>\n\"{8\"\niex> val\n31544\n```\n\nSee the documentation for [`<<>>`](`<<>>/1`) for a complete definition of pattern matching for binaries.\n\nFinally, remember that strings in Elixir are UTF-8 encoded binaries. This means that, similar to charlists, prefix matches on strings are also possible with the binary concatenation operator ([`<>`](`<>/2`)):\n\n```elixir\niex> \"hello \" <> world = \"hello world\"\n\"hello world\"\niex> world\n\"world\"\n```\n\nSuffix matches (`hello <> \" world\"`) are not valid patterns.\n\n## Guards\n\nGuards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed, such as function definitions, case clauses, and others.\n\nNot all expressions are allowed in guard clauses, but only a handful of them. This is a deliberate choice. This way, Elixir (through Erlang) ensures that all guards are predictable (no mutations or other side-effects) and they can be optimized and performed efficiently.\n\n### List of allowed functions and operators\n\nYou can find the built-in list of guards [in the `Kernel` module](`Kernel#guards`). Here is an overview:\n\n  * comparison operators ([`==`](`==/2`), [`!=`](`!=/2`), [`===`](`===/2`), [`!==`](`!==/2`),\n    [`<`](`</2`), [`<=`](`<=/2`), [`>`](`>/2`), [`>=`](`>=/2`)), [`max`](`max/2`), [`min`](`min/2`)\n  * strictly boolean operators ([`and`](`and/2`), [`or`](`or/2`), [`not`](`not/1`)). Note [`&&`](`&&/2`), [`||`](`||/2`), and [`!`](`!/1`) sibling operators are **not allowed** as they're not *strictly* boolean - meaning they don't require arguments to be booleans\n  * arithmetic unary operators ([`+`](`+/1`), [`-`](`-/1`))\n  * arithmetic binary operators ([`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), [`/`](`//2`))\n  * [`in`](`in/2`) and [`not in`](`in/2`) operators (as long as the right-hand side is a list or a range)\n  * \"type-check\" functions (`is_list/1`, `is_number/1`, and the like)\n  * functions that work on built-in data types (`abs/1`, `hd/1`, `map_size/1`, and others)\n  * the `map.field` syntax\n\nThe module `Bitwise` also includes a handful of [Erlang bitwise operations as guards](Bitwise.html#guards).\n\nMacros constructed out of any combination of the above guards are also valid guards - for example, `Integer.is_even/1`. For more information, see the \"Custom patterns and guards expressions\" section shown below.\n\n### Why guards\n\nLet's see an example of a guard used in a function clause:\n\n```elixir\ndef empty_map?(map) when map_size(map) == 0, do: true\ndef empty_map?(map) when is_map(map), do: false\n```\n\nGuards start with the `when` operator, followed by a guard expression. The clause will be executed if and only if the guard expression returns `true`. Multiple boolean conditions can be combined with the [`and`](`and/2`) and [`or`](`or/2`) operators.\n\nWriting the `empty_map?/1` function by only using pattern matching would not be possible (as pattern matching on `%{}` would match *any* map, not only the empty ones).\n\n### Non-passing guards\n\nA function clause will be executed if and only if its guard expression evaluates to `true`. If any other value is returned, the function clause will be skipped. In particular, guards have no concept of \"truthy\" or \"falsy\".\n\nFor example, imagine a function that checks that the head of a list is not `nil`:\n\n```elixir\ndef not_nil_head?([head | _]) when head, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> false\n```\n\nEven though the head of the list is not `nil`, the first clause for `not_nil_head?/1` fails because the expression does not evaluate to `true`, but to `\"some_value\"`, therefore triggering the second clause which returns `false`. To make the guard behave correctly, you must ensure that the guard evaluates to `true`, like so:\n\n```elixir\ndef not_nil_head?([head | _]) when head != nil, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> true\n```\n\n### Errors in guards\n\nIn guards, when functions would normally raise exceptions, they cause the guard to fail instead.\n\nFor example, the `tuple_size/1` function only works with tuples. If we use it with anything else, an argument error is raised:\n\n```elixir\niex> tuple_size(\"hello\")\n** (ArgumentError) argument error\n```\n\nHowever, when used in guards, the corresponding clause will fail to match instead of raising an error:\n\n```elixir\niex> case \"hello\" do\n...>   something when tuple_size(something) == 2 ->\n...>     :worked\n...>   _anything_else ->\n...>     :failed\n...> end\n:failed\n```\n\nIn many cases, we can take advantage of this. In the code above, we used `tuple_size/1` to both check that the given value is a tuple *and* check its size (instead of using `is_tuple(something) and tuple_size(something) == 2`).\n\nHowever, if your guard has multiple conditions, such as checking for tuples or maps, it is best to call type-check functions like `is_tuple/1` before `tuple_size/1`, otherwise the whole guard will fail if a tuple is not given. Alternatively, your function clause can use multiple guards as shown in the following section.\n\n### Multiple guards in the same clause\n\nThere exists an additional way to simplify a chain of `or` expressions in guards: Elixir supports writing \"multiple guards\" in the same clause. The following code:\n\n```elixir\ndef categorize_number(term) when is_integer(term) or is_float(term) or is_nil(term),\n  do: :maybe_number\ndef categorize_number(_other),\n  do: :something_else\n```\n\ncan be alternatively written as:\n\n```elixir\ndef categorize_number(term)\n    when is_integer(term)\n    when is_float(term)\n    when is_nil(term) do\n  :maybe_number\nend\n\ndef categorize_number(_other) do\n  :something_else\nend\n```\n\nIf each guard expression always returns a boolean, the two forms are equivalent. However, recall that if any function call in a guard raises an exception, the entire guard fails. To illustrate this, the following function will not detect empty tuples:\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and tuple_size/1 will not be evaluated\n  def empty?(val) when map_size(val) == 0 or tuple_size(val) == 0, do: true\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> false # true was expected!\n```\n\nThis could be corrected by ensuring that no exception is raised, either via type checks like `is_map(val) and map_size(val) == 0`, or by using multiple guards, so that if an exception causes one guard to fail, the next one is evaluated.\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and the second guard will be evaluated\n  def empty?(val)\n      when map_size(val) == 0\n      when tuple_size(val) == 0,\n      do: true\n\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> true\n```\n\n## Where patterns and guards can be used\n\nIn the examples above, we have used the match operator ([`=`](`=/2`)) and function clauses to showcase patterns and guards respectively. Here is the list of the built-in constructs in Elixir that support patterns and guards.\n\n  * `match?/2`:\n\n    ```elixir\n    match?({:ok, value} when value > 0, {:ok, 13})\n    ```\n\n  * function clauses:\n\n    ```elixir\n    def type(term) when is_integer(term), do: :integer\n    def type(term) when is_float(term), do: :float\n    ```\n\n  * [`case`](`case/2`) expressions:\n\n    ```elixir\n    case x do\n      1 -> :one\n      2 -> :two\n      n when is_integer(n) and n > 2 -> :larger_than_two\n    end\n    ```\n\n  * anonymous functions (`fn/1`):\n\n    ```elixir\n    larger_than_two? = fn\n      n when is_integer(n) and n > 2 -> true\n      n when is_integer(n) -> false\n    end\n    ```\n\n  * [`for`](`for/1`) and [`with`](`with/1`) support patterns and guards on the left side of `<-`:\n\n    ```elixir\n    for x when x >= 0 <- [1, -2, 3, -4], do: x\n    ```\n\n    `with` also supports the `else` keyword, which supports patterns matching and guards.\n\n  * [`try`](`try/1`) supports patterns and guards on `catch` and `else`\n\n  * [`receive`](`receive/1`) supports patterns and guards to match on the received messages.\n\n  * custom guards can also be defined with `defguard/1` and `defguardp/1`. A custom guard can only be defined based on existing guards.\n\nNote that the match operator ([`=`](`=/2`)) does *not* support guards:\n\n```elixir\n{:ok, binary} = File.read(\"some/file\")\n```\n\n## Custom patterns and guards expressions\n\nOnly the constructs listed in this page are allowed in patterns and guards. However, we can take advantage of macros to write custom patterns 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 boils down to a combination of the constructs above.\n\nFor example, the `Record` module in Elixir provides a series of macros to be used in patterns and guards that allows tuples to have named fields during compilation.\n\nFor defining your own guards, Elixir even provides conveniences in `defguard` and `defguardp`. Let's look at a quick case study: we want to check whether an argument is an even or an odd integer. With pattern matching this is impossible because there is an infinite number of integers, and therefore we can't pattern match on every single one of them. Therefore we must use guards. We will just focus on checking for even numbers since checking for the odd ones is almost identical.\n\nSuch a guard would look like this:\n\n```elixir\ndef my_function(number) when is_integer(number) and rem(number, 2) == 0 do\n  # do stuff\nend\n```\n\nIt would be repetitive to write every time we need this check. Instead, you can use `defguard/1` and `defguardp/1` to create guard macros. Here's an example how:\n\n```elixir\ndefmodule MyInteger do\n  defguard is_even(term) when is_integer(term) and rem(term, 2) == 0\nend\n```\n\nand then:\n\n```elixir\nimport MyInteger, only: [is_even: 1]\n\ndef my_function(number) when is_even(number) do\n  # do stuff\nend\n```\n\nWhile it's possible to create custom guards with macros, it's recommended to define them using `defguard/1` and `defguardp/1` which perform additional compile-time checks.\n","lib/elixir/pages/references/gradual-set-theoretic-types.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Gradual set-theoretic types\n\nElixir is in the process of incorporating set-theoretic types into the compiler. This document outlines the current stage of our implementation for this Elixir version. Elixir's type system is:\n\n  * **sound** - the inferred and assigned by the type system align with the behaviour of the program\n\n  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. However, instead of simply discarding all typing information, Elixir's `dynamic()` type works as a range. For example, if you write `dynamic(integer() or binary())`, Elixir's type system will still emit violations if none of those types are accepted. Furthermore, in the absence of `dynamic()`, Elixir's type system behaves as a static one\n\n  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)\n\nThe current milestone aims to infer types from existing programs and use them for type checking, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. User provided type signatures are planned for future releases. The underlying principles, theory, and roadmap of our work have been outlined in [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).\n\n## A gentle introduction\n\nTypes in Elixir are written using the type named followed by parentheses, such as `integer()` or `list(integer())`.\n\nThe basic types are:\n\n```elixir\natom()\nbinary()\nbitstring()\nempty_list()\ninteger()\nfloat()\nfunction()\nmap()\nnon_empty_list(elem_type, tail_type)\npid()\nport()\nreference()\ntuple()\n```\n\nMany of the types above can also be written more precisely. We will discuss their syntax in the next sections, but here are two examples:\n\n  * While `atom()` represents all atoms, the atom `:ok` can also be represented in the type system as `:ok`\n\n  * While `tuple()` represents all tuples, you can specify the type of a two-element tuple where the first element is the atom `:ok` and the second is an integer as `{:ok, integer()}`\n\nThere are also three special types: `none()` (represents an empty set), `term()` (represents all types), `dynamic()` (represents a range of the given types).\n\nGiven the types are set-theoretic, we can compose them using unions (`or`), intersections (`and`), and negations (`not`). For example, to say a function returns either atoms or integers, one could write: `atom() or integer()`.\n\nIntersections will find the elements in common between the operands. For example, `atom() and integer()`, which in this case is the empty set `none()`. You can combine intersections and negations to perform difference, for example, to say that a function expects all atoms, except `nil` (which is an atom), you could write: `atom() and not nil`.\n\nYou can find a complete reference in the [set-theoretic types cheatsheet](../cheatsheets/types-cheat.cheatmd).\n\n## The syntax of data types\n\nIn this section we will cover the syntax of all data types. At the moment, developers will interact with those types mostly through compiler warnings and diagnostics.\n\n### Broad types\n\nThese types are broad in that they cannot represent individual elements, only the whole set. For example, the numbers `1` and `42` are both represented by the type `integer()`.\n\nThey are: `binary()`, `bitstring()`, `integer()`, `float()`, `pid()`, `port()`, `reference()`.\n\nThe `binary()` type is a subtype of the less frequently used `bitstring()` type, as binaries are bitstrings where the number of bits is divisible by 8.\n\n### Atoms\n\nYou can represent all atoms as `atom()`. You can also represent each individual atom using their literal syntax. For instance, the atom `:foo` and `:hello_world` are also valid (distinct) types.\n\n`nil`, `true`, and `false` are also atoms and can be written as is. `boolean()` is a convenience type alias that represents `true or false`.\n\n### Tuples\n\nYou can represent all tuples as `tuple()`. Tuples may also be written using the curly brackets syntax, such as `{:ok, binary()}`.\n\nYou may use `...` at the end of the tuple to imply the overall size of the tuple is unknown. For example, the following tuple has at least two elements: `{:ok, binary(), ...}`.\n\n### Lists\n\nYou can represent all _proper_ lists as `list()`, which also includes the empty list.\n\nYou can also specify the type of the list element as argument. For example, `list(integer())` represents the values `[]` and `[1, 2, 3]`, but not `[1, \"two\", 3]`.\n\nInternally, Elixir represents the type `list(a)` as the union two distinct types, `empty_list()` and `non_empty_list(a)`. In other words, `list(integer())` is equivalent to `empty_list() or non_empty_list(integer())`.\n\n#### Improper lists\n\nWhile most developers will simply use `list(a)`, the type system can express all different representations of lists in Elixirby passing a second argument to `non_empty_list`, which represents the type of the tail.\n\nA proper list is one where the tail is the empty list itself. The type `non_empty_list(integer())` is equivalent to `non_empty_list(integer(), empty_list())`.\n\nIf the `tail_type` is anything but a list, then we have an improper list. For example, the value `[1, 2 | 3]` would have the type `non_empty_list(integer(), integer())`.\n\nIf you pass a list type as the tail, then the list type is merged into the element type. For example, `non_empty_list(integer(), list(binary()))` is the same as `non_empty_list(integer() or binary(), empty_list())`.\n\n### Maps\n\nYou can represent all maps as `map()`.\n\nMaps may also be written using their literal syntax:\n\n```elixir\n%{name: binary(), age: integer()}\n```\n\nwhich outlines a map with exactly two keys, `:name` and `:age`, and values of type `binary()` and `integer()` respectively. We say the map above is \"closed\": it only supports the keys explicitly defined. We can also mark a map as \"open\", by including `...` as its first element:\n\n```elixir\n%{..., name: binary(), age: integer()}\n```\n\nThe type above says the keys `:name` and `:age` must exist, with their respective types, but other keys may be present. The `map()` type is the same as `%{...}`. For the empty map, you may write `%{}`, although we recommend using `empty_map()` for clarity.\n\n#### Optional keys\n\nA key may be marked as optional using the `if_set/1` operation on its value type:\n\n```elixir\n%{name: binary(), age: if_set(integer())}\n```\n\nis a map that certainly has the `:name` key but it may have the `:age` key (and if it has such key, its value type is `integer()`).\n\nYou can also use `not_set()` to denote a key cannot be present:\n\n```elixir\n%{..., age: not_set()}\n```\n\nThe type above says the map may have any key, except the `:age` one. This is, for instance, the type returned by `Map.delete(map, :age)`.\n\n#### Domain types\n\nIn the examples above, all map keys were atoms, but we can also use other types as map keys. For example:\n\n```elixir\n# Closed map\n%{binary() or atom() => integer()}\n\n# Open map\n%{..., binary() or atom() => integer()}\n```\n\nCurrently, the type system only tracks the top of each individual type as the domain keys. For example, if you say:\n\n```elixir\n%{list(integer()) => integer(), list(binary()) => binary()}\n```\n\nThat's the same as specifying all lists:\n\n```elixir\n%{list() => integer() or binary()}\n```\n\nThe supported domain keys are `atom()`, `bitstring()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, and `tuple()`. In the case of maps, the `bitstring()` domain stores exclusively keys which are not binary. The ones which are `binary()` are stored under the `binary()` domain.\n\nFurthermore, it is important to note that domain keys are, by definition, optional. Whenever you have a `%{integer() => integer()}`and you try to fetch a key, we must assume the key may not exist (after all, it is not possible to store all integers as map keys as they are infinite).\n\n#### Mixed keys\n\nIt is also possible to mix domain and atom keys. For example, the following map says that all atom keys are of type `binary()`, except the `:root` key, which has type `integer()`:\n\n```elixir\n# Closed map\n%{atom() => binary(), root: integer()}\n\n# Open map\n%{..., atom() => binary(), root: integer()}\n```\n\nThe order of the keys is of increasing precision. `:root` is more precise than `atom()`, therefore it comes later. This mirrors the runtime semantics of maps, where duplicate keys override the value of earlier ones.\n\n### Functions\n\nYou can represent all functions as `function()`.  However, in practice, most functions are represented as arrows. For example, a function that receives an integer and return boolean would be written as `(integer() -> boolean())`. A function that receives two integers and return a string (i.e. a binary) would be written as `(integer(), integer() -> binary())`.\n\nWhen representing functions with multiple clauses, which may take different input types, we use intersections. For example, imagine the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nIf you give it an integer, it negates it. If you give it a boolean, it negates it.\n\nWe can say this function has the type `(integer() -> integer())` because it is capable of receiving an integer and returning an integer. In this case, `(integer() -> integer())` is a set that represents all functions that can receive an integer and return an integer. Even though this function can receive other arguments and return other values, it is still part of the `(integer() -> integer())` set.\n\nThis function also has the type `(boolean() -> boolean())`, because it also receives booleans and returns booleans. If you pass the function above to another function that expects `(boolean() -> boolean())`, type checking will succeed. Therefore, we can say the overall type of the function is `(integer() -> integer()) and (boolean() -> boolean())`. The intersection means the function belongs to both sets.\n\nAt this point, you may ask, why not a union? As a real-world example, take a t-shirt with green and yellow stripes. We can say the t-shirt belongs to the set of \"t-shirts with green color\". We can also say the t-shirt belongs to the set of \"t-shirts with yellow color\". Let's see the difference between unions and intersections:\n\n  * `(t_shirts_with_green() or t_shirts_with_yellow())` - contains t-shirts with either green or yellow, such as green, green and red, green and yellow, but also only yellow, yellow and red, etc.\n\n  * `(t_shirts_with_green() and t_shirts_with_yellow())` - contains t-shirts with both green and yellow (and maybe other colors)\n\nSince the t-shirt has both colors, we could say it belongs to the union of green and yellow t-shirts, but doing so would not capture the fact it is both green and yellow. Therefore it is more precise to say it belongs to the intersection of both sets. The same way that a function that goes from `(integer() -> integer())` and `(boolean() -> boolean())` is also an intersection. In practice, it is not useful to define the union of two functions in Elixir, so the compiler will point you to the right direction if you specify the wrong one.\n\n## The `dynamic()` type\n\nExisting Elixir programs do not have type declarations, but we still want to be able to type check them. This is done with the introduction of the `dynamic()` type.\n\nWhen Elixir sees the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nElixir type checks it as if the function had the type `(dynamic() -> dynamic())`. Then, based on patterns and guards, we can refine the value of the variable `x` to be `dynamic() and integer()` and `dynamic() and boolean()` for each clause respectively. We say `dynamic()` is a gradual type, which leads us to _gradual set-theoretic types_.\n\nThe simplest way to reason about `dynamic()` in Elixir is that it is a range of types. If you have a type `atom() or integer()`, the underlying code needs to work with both `atom() or integer()`. For example, if you call `Integer.to_string(var)`, and `var` has type `atom() or integer()`, the type system will emit a warning, because `Integer.to_string/1` does not accept atoms.\n\nHowever, by intersecting a type with `dynamic()`, we make the type gradual and therefore only a subset of the type needs to be valid. For instance, if you call `Integer.to_string(var)`, and `var` has type `dynamic() and (atom() or integer())`, the type system will not emit a warning, because `Integer.to_string/1` works with at least one of the types. For convenience, most programs will write `dynamic(atom() or integer())` instead of the intersection. They are equivalent.\n\nCompared to other gradually typed languages, the `dynamic()` type in Elixir is quite powerful: it restricts our program to certain types, via intersections, while still emitting warnings once it is certain the code will fail. This makes `dynamic()` an excellent tool for typing existing Elixir code with meaningful warnings.\n\nIf the user provides their own types, and those types are not `dynamic()`, then Elixir's type system behaves as a statically typed one. This brings us to one last property of dynamic types in Elixir: dynamic types are always at the root. For example, when you write a tuple of type `{:ok, dynamic()}`, Elixir will rewrite it to `dynamic({:ok, term()})`. While this has the downside that you cannot make part of a tuple/map/list gradual, only the whole tuple/map/list, it comes with the upside that dynamic is always explicitly at the root, making it harder to accidentally sneak `dynamic()` in a statically typed program.\n\n## Type inference\n\nType inference (or reconstruction) is the ability of a type system to automatically deduce, either partially or fully, the type of an expression at compile time. Type inference may occur at different levels. For example, many programming languages can automatically infer the types of variables, also known \"local type inference\", but not all can infer type signatures of functions.\n\nInferring type signatures comes with a series of trade-offs:\n\n  * Speed - type inference algorithms are often more computationally intensive than type checking algorithms.\n\n  * Expressiveness - in any given type system, the constructs that support inference are always a subset of those that can be type-checked. Therefore, if a programming language is restricted to fully reconstructed types, it is less expressive than a solely type checked counterpart.\n\n  * Incremental compilation - type inference complicates incremental compilation. If module A depends on module B, which depends on module C, a change to C may require the type signature in B to be reconstructed, which may then require A to be recomputed (and so on). This dependency chain may require large projects to explicitly add type signatures for stability and compilation efficiency.\n\n  * Cascading errors - when a user accidentally makes type errors or the code has conflicting assumptions, type inference may lead to less clear error messages as the type system tries to reconcile diverging type assumptions across code paths.\n\nOn the other hand, type inference offers the benefit of enabling type checking for functions and codebases without requiring the user to add type annotations. To balance these trade-offs, Elixir aims to provide type inference across dependencies: our goal is to infer the types of functions considering the current module, Elixir's standard library and your dependencies, while calls to modules within the same project are assumed to be `dynamic()`. Once types are inferred, then the whole project is type checked considering all modules and all types (inferred or otherwise).\n\nType inference in Elixir is best-effort: it doesn't guarantee it will find all possible type incompatibilities, only that it may find bugs where all combinations of a type _will_ fail, even in the absence of explicit type annotations. It is meant to be an efficient routine that brings developers some benefits of static typing, without requiring any effort from them and keeping the expressiveness of the language.\n\nIn the long term, Elixir developers who want static typing guarantees may explicitly add type signatures to their functions (see \"Roadmap\"). Any function with an explicit type signature will be typed checked against the user-provided annotations, as in other statically typed languages.\n\n### False positives\n\nElixir's type inference generally avoids emitting false positive type violations: which are warnings emitted by the type checker when there are no runtime errors. However, in some situations, those may happen and are documented below.\n\n#### `for`-comprehensions assume they may be executed zero, once, or multiple times\n\nFor comprehensions in Elixir assume they are executed at least once. Take this code:\n\n```elixir\ndef example(x, list) do\n  for _i <- list do\n    Atom.to_string(x)\n  end\n\n  x + 1\nend\n```\n\n`x + 1` will fail because it assumes `x` is an atom from the `Atom.to_string(x)` call, even though the function may raise no runtime error if `list` is an empty list. This is intentional, as it helps find discrepancies inside and outside comprehensions. You can address this by explicitly wrapping the comprehension in a `if list != [] do` block (or similar condition).\n\nSimilar, when using the `:reduce` option, Elixir assumes the list may be empty and therefore the accumulator must match the result type. Take this contrived example:\n\n```elixir\ndef example([_ | _] = list) do\n  Integer.to_string(\n    for i <- list, reduce: :unused do\n      _unused -> i * 2\n    end\n  )\nend\n```\n\nEven though the list is non-empty, for-comprehension always assumes the list can be empty, and the code above will fail because passing `:unused` to `Integer.to_string/1` is a typing violation (which will happen if list is empty). You fix this by making sure the accumulator matches the type of the comprehension body.\n\n#### Struct update syntax must be statically proven\n\nElixir will warn if you use the struct update syntax and it is not statically proven that the given value does not have said struct type. For example:\n\n```elixir\nuser = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\nEven though it is guaranteed at runtime that user is always a `User` struct. If the type system cannot prove it, it will emit a typing violation. This is how struct updates work by design. In such cases, you can address it by matching on the struct when the user variable is defined:\n\n```elixir\n%User{} = user = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\n## Roadmap\n\nAt this moment, Elixir implements type inference of all language constructs. The goal is to assess performance and collect feedback on the quality of error messages, before introducing user facing types.\n\nIf the results are satisfactory, the next milestone will include a mechanism for defining typed structs. Elixir programs frequently pattern match on structs, which reveals information about the struct fields, but it knows nothing about their respective types. By propagating types from structs and their fields throughout the program, we will increase the type system’s ability to find errors while further straining our type system implementation. Proposals including the required changes to the language surface will be sent to the community once we reach this stage.\n\nThe third milestone is to introduce set-theoretic type signatures for functions. Unfortunately, the existing Erlang Typespecs are not precise enough for set-theoretic types and they will be phased out of the language and have their postprocessing moved into a separate library once this stage concludes.\n\n## Resources\n\n  * (Paper) [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391)\n  * (Video) [\"The foundations of the Elixir type system\" by José Valim](https://youtu.be/giYbq4HmfGA)\n  * (Video) [\"Precision in type system design\" by José Valim](https://youtu.be/Ay-gnCqDw9o?t=102)\n\n## Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), and [Tidewave](https://tidewave.ai/).\n","lib/elixir/pages/references/compatibility-and-deprecations.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Compatibility and deprecations\n\nElixir is versioned according to a vMAJOR.MINOR.PATCH schema.\n\nElixir is currently at major version v1. A new backwards compatible minor release happens every 6 months. Patch releases are not scheduled and are made whenever there are bug fixes or security patches.\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.21           | Development\n1.20           | Bug fixes and security patches\n1.19           | Security patches only\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann) and on the [GitHub releases page](https://github.com/elixir-lang/elixir/releases).\n\nYou may also see [all releases](https://github.com/elixir-lang/elixir/releases) and [consult all disclosed vulnerabilities](https://github.com/elixir-lang/elixir/security) on GitHub.\n\nThere are currently no plans for a major v2 release.\n\n## Between non-major Elixir versions\n\nElixir minor and patch releases are backwards compatible: well-defined behaviors and documented APIs in a given version will continue working on future versions.\n\nAlthough we expect the vast majority of programs to remain compatible over time, it is impossible to guarantee that no future change will break any program. Under some unlikely circumstances, we may introduce changes that break existing code:\n\n  * Security: a security issue in the implementation may arise whose resolution requires backwards incompatible changes. We reserve the right to address such security issues.\n\n  * Bugs: if an API has undesired behavior, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.\n\n  * Compiler front-end: improvements may be done to the compiler, introducing new warnings for ambiguous modes and providing more detailed error messages. Those can lead to compilation errors (when running with `--warnings-as-errors`) or tooling failures when asserting on specific error messages (although one should avoid such). We reserve the right to do such improvements.\n\n  * Imports: new functions may be added to the `Kernel` module, which is auto-imported. They may collide with local functions defined in your modules. Collisions can be resolved in a backwards compatible fashion using `import Kernel, except: [...]` with a list of all functions you don't want to be imported from `Kernel`. We reserve the right to do such additions.\n\nIn order to continue evolving the language without introducing breaking changes, Elixir will rely on deprecations to demote certain practices and promote new ones. Our deprecation policy is outlined in the [\"Deprecations\" section](#deprecations).\n\nThe only exception to the compatibility guarantees above are experimental features, which will be explicitly marked as such, and do not provide any compatibility guarantee until they are stabilized.\n\n## Between Elixir and Erlang/OTP\n\nErlang/OTP versioning is independent from the versioning of Elixir. Erlang releases a new major version yearly. Our goal is to support the last three Erlang major versions by the time Elixir is released. The compatibility table is shown below.\n\nElixir version | Supported Erlang/OTP versions\n:------------- | :-------------------------------\n1.21           | 27 - 29\n1.20           | 27 - 29\n1.19           | 26 - 28\n1.18           | 25 - 27\n1.17           | 25 - 27\n1.16           | 24 - 26\n1.15           | 24 - 26\n1.14           | 23 - 25 (and Erlang/OTP 26 from v1.14.5)\n1.13           | 22 - 24 (and Erlang/OTP 25 from v1.13.4)\n1.12           | 22 - 24\n1.11           | 21 - 23 (and Erlang/OTP 24 from v1.11.4)\n1.10           | 21 - 22 (and Erlang/OTP 23 from v1.10.3)\n1.9            | 20 - 22\n1.8            | 20 - 22\n1.7            | 19 - 22\n1.6            | 19 - 20 (and Erlang/OTP 21 from v1.6.6)\n1.5            | 18 - 20\n1.4            | 18 - 19 (and Erlang/OTP 20 from v1.4.5)\n1.3            | 18 - 19\n1.2            | 18 - 18 (and Erlang/OTP 19 from v1.2.6)\n1.1            | 17 - 18\n1.0            | 17 - 17 (and Erlang/OTP 18 from v1.0.5)\n\nElixir may add compatibility to new Erlang/OTP versions on patch releases, such as support for Erlang/OTP 20 in v1.4.5. Those releases are made for convenience and typically contain the minimum changes for Elixir to run without errors, if any changes are necessary. Only the next minor release, in this case v1.5.0, effectively leverages the new features provided by the latest Erlang/OTP release.\n\n## Deprecations\n\n### Policy\n\nElixir deprecations happen in 3 steps:\n\n  1. The feature is soft-deprecated. It means both CHANGELOG and documentation must list the feature as deprecated but no warning is effectively emitted by running the code. There is no requirement to soft-deprecate a feature.\n\n  2. The feature is effectively deprecated by emitting warnings on usage. This is also known as hard-deprecation. In order to deprecate a feature, the proposed alternative MUST exist for AT LEAST THREE minor versions. For example, `Enum.uniq/2` was soft-deprecated in favor of `Enum.uniq_by/2` in Elixir v1.1. This means a deprecation warning may only be emitted by Elixir v1.4 or later.\n\n  3. The feature is removed. This can only happen on major releases. This means deprecated features in Elixir v1.x shall only be removed by Elixir v2.x.\n\n### Table of deprecations\n\nThe first column is the version the feature was hard deprecated. The second column shortly describes the deprecated feature and the third column explains the replacement and from which the version the replacement is available from.\n\nVersion | Deprecated feature                                  | Replaced by (available since)\n:-------| :-------------------------------------------------- | :---------------------------------------------------------------\n[v1.21] | `Macro.Env.fetch_alias/2` (and `fetch_macro_alias`) | `Macro.Env.expand_alias/4` (v1.17)\n[v1.20] | `<<x::size(y)>>` in patterns without `^`            | `<<x::size(^y)>>` (v1.15)\n[v1.20] | `File.stream!(path, modes, lines_or_bytes)`         | `File.stream!(path, lines_or_bytes, modes)` (v1.16)\n[v1.20] | `Kernel.ParallelCompiler.async/1`                   | `Kernel.ParallelCompiler.pmap/2` (v1.16)\n[v1.20] | `Logger.*_backend` functions                        | The `LoggerBackends` module from [`:logger_backends`](https://hex.pm/packages/logger_backends) package\n[v1.20] | `Logger.enable/1` and `Logger.disable/1`            | `Logger.put_process_level/2` and `Logger.delete_process_level/1` respectively (v1.15)\n[v1.19] | CLI configuration in `def project` inside `mix.exs` | Moving it to `def cli` (v1.14)\n[v1.19] | Using `,` to separate tasks in `mix do`             | Using `+` (v1.14)\n[v1.19] | `Logger`'s `:backends` configuration                | `Logger`'s `:default_handler` configuration (v1.15)\n[v1.19] | Passing a callback to `File.cp/3`, `File.cp!/3`, `File.cp_r/3`, and `File.cp_r!/3` | The `:on_conflict` option (v1.14)\n[v1.18] | `<%#` in EEx                                        | `<%!--` (v1.14) or `<% #` (v1.0)\n[v1.18] | `EEx.Engine.handle_text/2` callback in EEx          | `c:EEx.Engine.handle_text/3` (v1.14)\n[v1.18] | Returning a 2-arity function from `Enumerable.slice/1` | Returning a 3-arity function (v1.14)\n[v1.18] | Ranges with negative steps in `Range.new/2`         | Explicit steps in ranges (v1.11)\n[v1.18] | `Tuple.append/2`                                    | `Tuple.insert_at/3` (v1.0)\n[v1.18] | `mix cmd --app APP`                                 | `mix do --app APP` (v1.14)\n[v1.18] | `List.zip/1`                                        | `Enum.zip/1` (v1.0)\n[v1.18] | `Module.eval_quoted/3`                              | `Code.eval_quoted/3` (v1.0)\n[v1.17] | Single-quoted charlists (`'foo'`)                   | `~c\"foo\"` (v1.0)\n[v1.17] | `left..right` in patterns and guards                | `left..right//step` (v1.11)\n[v1.17] | `ExUnit.Case.register_test/4`                       | `register_test/6` (v1.10)\n[v1.17] | `:all` in `IO.read/2` and `IO.binread/2`            | `:eof` (v1.13)\n[v1.16] | `~R/.../`                                           | `~r/.../` (v1.0)\n[v1.16] | Ranges with negative steps in `Enum.slice/2`        | Explicit steps in ranges (v1.11)\n[v1.16] | Ranges with negative steps in `String.slice/2`      | Explicit steps in ranges (v1.11)\n[v1.15] | `Calendar.ISO.day_of_week/3`                        | `Calendar.ISO.day_of_week/4` (v1.11)\n[v1.15] | `Exception.exception?/1`                            | `Kernel.is_exception/1` (v1.11)\n[v1.15] | `Regex.regex?/1`                                    | `Kernel.is_struct/2` (`Kernel.is_struct(term, Regex)`) (v1.11)\n[v1.15] | `Logger.warn/2`                                     | `Logger.warning/2` (v1.11)\n[v1.14] | `use Bitwise`                                       | `import Bitwise` (v1.0)\n[v1.14] | `~~~/1`                                             | `bnot/1` (v1.0)\n[v1.14] | `Application.get_env/3` and similar in module body  | `Application.compile_env/3` (v1.10)\n[v1.14] | Compiled patterns in `String.starts_with?/2`        | Pass a list of strings instead (v1.0)\n[v1.14] | `Mix.Tasks.Xref.calls/1`                            | Compilation tracers (outlined in `Code`) (v1.10)\n[v1.14] | `$levelpad` in Logger                               | *None*\n[v1.14] | `<\\|>` as a custom operator                         | Another custom operator (v1.0)\n[v1.13] | `!` and `!=` in Version requirements                | `~>` or `>=` (v1.0)\n[v1.13] | `Mix.Config`                                        | `Config` (v1.9)\n[v1.13] | `:strip_beam` config to `mix escript.build`         | `:strip_beams` (v1.9)\n[v1.13] | `Macro.to_string/2`                                 | `Macro.to_string/1` (v1.0)\n[v1.13] | `System.get_pid/0`                                  | `System.pid/0` (v1.9)\n[v1.12] | `^^^/2`                                             | `bxor/2` (v1.0)\n[v1.12] | `@foo()` to read module attributes                  | Remove the parenthesis (v1.0)\n[v1.12] | `use EEx.Engine`                                    | Explicitly delegate to EEx.Engine instead (v1.0)\n[v1.12] | `:xref` compiler in Mix                             | Nothing (it always runs as part of the compiler now)\n[v1.11] | `Mix.Project.compile/2`                             | `Mix.Task.run(\"compile\", args)` (v1.0)\n[v1.11] | `Supervisor.Spec.worker/3` and `Supervisor.Spec.supervisor/3` | The new child specs outlined in `Supervisor` (v1.5)\n[v1.11] | `Supervisor.start_child/2` and `Supervisor.terminate_child/2` | `DynamicSupervisor` (v1.6)\n[v1.11] | `System.stacktrace/0`                               | `__STACKTRACE__` in `try/catch/rescue` (v1.7)\n[v1.10] | `Code.ensure_compiled?/1`                           | `Code.ensure_compiled/1` (v1.0)\n[v1.10] | `Code.load_file/2`                                  | `Code.require_file/2` (v1.0) or `Code.compile_file/2` (v1.7)\n[v1.10] | `Code.loaded_files/0`                               | `Code.required_files/0` (v1.7)\n[v1.10] | `Code.unload_file/1`                                | `Code.unrequire_files/1` (v1.7)\n[v1.10] | Passing non-chardata to `Logger.log/2`              | Explicitly convert to string with `to_string/1` (v1.0)\n[v1.10] | `:compile_time_purge_level` in `Logger` app environment | `:compile_time_purge_matching` in `Logger` app environment (v1.7)\n[v1.10] | `Supervisor.Spec.supervise/2`                       | The new child specs outlined in `Supervisor` (v1.5)\n[v1.10] | `:simple_one_for_one` strategy in `Supervisor`      | `DynamicSupervisor` (v1.6)\n[v1.10] | `:restart` and `:shutdown` in `Task.Supervisor.start_link/1` | `:restart` and `:shutdown` in `Task.Supervisor.start_child/3` (v1.6)\n[v1.9]  | Enumerable keys in `Map.drop/2`, `Map.split/2`, and `Map.take/2` | Call `Enum.to_list/1` on the second argument before hand (v1.0)\n[v1.9]  | `Mix.Project.load_paths/1`                          | `Mix.Project.compile_path/1` (v1.0)\n[v1.9]  | Passing `:insert_replaced` to `String.replace/4`    | Use `:binary.replace/4` (v1.0)\n[v1.8]  | Passing a non-empty list to `Collectable.into/1`    | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `:into` in `for/1`      | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `Enum.into/2`           | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Time units in its plural form, such as: `:seconds`, `:milliseconds`, and the like | Use the singular form, such as: `:second`, `:millisecond`, and so on (v1.4)\n[v1.8]  | `Inspect.Algebra.surround/3`                        | `Inspect.Algebra.concat/2` and `Inspect.Algebra.nest/2` (v1.0)\n[v1.8]  | `Inspect.Algebra.surround_many/6`                   | `Inspect.Algebra.container_doc/6` (v1.6)\n[v1.9]  | `--detached` in `Kernel.CLI`                        | `--erl \"-detached\"` (v1.0)\n[v1.8]  | `Kernel.ParallelCompiler.files/2`                   | `Kernel.ParallelCompiler.compile/2` (v1.6)\n[v1.8]  | `Kernel.ParallelCompiler.files_to_path/2`           | `Kernel.ParallelCompiler.compile_to_path/2` (v1.6)\n[v1.8]  | `Kernel.ParallelRequire.files/2`                    | `Kernel.ParallelCompiler.require/2` (v1.6)\n[v1.8]  | Returning `{:ok, contents}` or `:error` from `Mix.Compilers.Erlang.compile/6`'s callback | Return `{:ok, contents, warnings}` or `{:error, errors, warnings}` (v1.6)\n[v1.8]  | `System.cwd/0` and `System.cwd!/0`                  | `File.cwd/0` and `File.cwd!/0` respectively (v1.0)\n[v1.7]  | `Code.get_docs/2`                                   | `Code.fetch_docs/1` (v1.7)\n[v1.7]  | `Enum.chunk/2,3,4`                                  | `Enum.chunk_every/2` and [`Enum.chunk_every/3,4`](`Enum.chunk_every/4`) (v1.5)\n[v1.7]  | Calling `super/1` in`GenServer` callbacks           | Implementing the behaviour explicitly without calling `super/1` (v1.0)\n[v1.7]  | [`not left in right`](`in/2`)                | [`left not in right`](`in/2`) (v1.5)\n[v1.7]  | `Registry.start_link/3`                             | `Registry.start_link/1` (v1.5)\n[v1.7]  | `Stream.chunk/2,3,4`                                | `Stream.chunk_every/2` and [`Stream.chunk_every/3,4`](`Stream.chunk_every/4`) (v1.5)\n[v1.6]  | `Enum.partition/2`                                  | `Enum.split_with/2` (v1.4)\n[v1.6]  | `Macro.unescape_tokens/1,2`                         | Use `Enum.map/2` to traverse over the arguments (v1.0)\n[v1.6]  | `Module.add_doc/6`                                  | [`@doc`](`Module`) module attribute (v1.0)\n[v1.6]  | `Range.range?/1`                                    | Pattern match on [`_.._`](`../2`) (v1.0)\n[v1.5]  | `()` to mean `nil`                                  | `nil` (v1.0)\n[v1.5]  | `char_list/0` type                                  | `t:charlist/0` type (v1.3)\n[v1.5]  | `Atom.to_char_list/1`                               | `Atom.to_charlist/1` (v1.3)\n[v1.5]  | `Enum.filter_map/3`                                 | `Enum.filter/2` + `Enum.map/2` or `for/1` comprehensions (v1.0)\n[v1.5]  | `Float.to_char_list/1`                              | `Float.to_charlist/1` (v1.3)\n[v1.5]  | `GenEvent` module                                   | `Supervisor` and `GenServer` (v1.0)\n[v1.5]  | `<%=` in middle and end expressions in `EEx`        | Use `<%` (`<%=` is allowed only in start expressions) (v1.0)\n[v1.5]  | `:as_char_lists` value in `t:Inspect.Opts.t/0` type | `:as_charlists` value (v1.3)\n[v1.5]  | `:char_lists` key in `t:Inspect.Opts.t/0` type      | `:charlists` key (v1.3)\n[v1.5]  | `Integer.to_char_list/1,2`                          | `Integer.to_charlist/1` and `Integer.to_charlist/2` (v1.3)\n[v1.5]  | `to_char_list/1`                                    | `to_charlist/1` (v1.3)\n[v1.5]  | `List.Chars.to_char_list/1`                         | `List.Chars.to_charlist/1` (v1.3)\n[v1.5]  | `@compile {:parse_transform, _}` in `Module`        | *None*\n[v1.5]  | `Stream.filter_map/3`                               | `Stream.filter/2` + `Stream.map/2` (v1.0)\n[v1.5]  | `String.ljust/3` and `String.rjust/3`               | Use `String.pad_leading/3` and `String.pad_trailing/3` with a binary padding (v1.3)\n[v1.5]  | `String.lstrip/1` and `String.rstrip/1`             | `String.trim_leading/1` and `String.trim_trailing/1` (v1.3)\n[v1.5]  | `String.lstrip/2` and `String.rstrip/2`             | Use `String.trim_leading/2` and `String.trim_trailing/2` with a binary as second argument (v1.3)\n[v1.5]  | `String.strip/1` and `String.strip/2`               | `String.trim/1` and `String.trim/2` (v1.3)\n[v1.5]  | `String.to_char_list/1`                             | `String.to_charlist/1` (v1.3)\n[v1.4]  | Anonymous functions with no expression after `->`   | Use an expression or explicitly return `nil` (v1.0)\n[v1.4]  | Support for making [private functions](`defp/2`) overridable | Use [public functions](`def/2`) (v1.0)\n[v1.4]  | Variable used as function call                      | Use parentheses (v1.0)\n[v1.4]  | `Access.key/1`                                      | `Access.key/2` (v1.3)\n[v1.4]  | `Behaviour` module                                  | `@callback` module attribute (v1.0)\n[v1.4]  | `Enum.uniq/2`                                       | `Enum.uniq_by/2` (v1.2)\n[v1.4]  | `Float.to_char_list/2`                              | `:erlang.float_to_list/2` (Erlang/OTP 17)\n[v1.4]  | `Float.to_string/2`                                 | `:erlang.float_to_binary/2` (Erlang/OTP 17)\n[v1.4]  | `HashDict` module                                   | `Map` (v1.2)\n[v1.4]  | `HashSet` module                                    | `MapSet` (v1.1)\n[v1.4]  | `IEx.Helpers.import_file/2`                         | `IEx.Helpers.import_file_if_available/1` (v1.3)\n[v1.4]  | `Mix.Utils.camelize/1`                              | `Macro.camelize/1` (v1.2)\n[v1.4]  | `Mix.Utils.underscore/1`                            | `Macro.underscore/1` (v1.2)\n[v1.4]  |  Multi-letter aliases in `OptionParser`             | Use single-letter aliases (v1.0)\n[v1.4]  | `Set` module                                        | `MapSet` (v1.1)\n[v1.4]  | `Stream.uniq/2`                                     | `Stream.uniq_by/2` (v1.2)\n[v1.3]  | `\\x{X*}` inside strings/sigils/charlists            | `\\uXXXX` or `\\u{X*}` (v1.1)\n[v1.3]  | `Dict` module                                       | `Keyword` (v1.0) or `Map` (v1.2)\n[v1.3]  | `:append_first` option in `defdelegate/2`           | Define the function explicitly (v1.0)\n[v1.3]  | Map/dictionary as 2nd argument in `Enum.group_by/3` | `Enum.reduce/3` (v1.0)\n[v1.3]  | `Keyword.size/1`                                    | `length/1` (v1.0)\n[v1.3]  | `Map.size/1`                                        | `map_size/1` (v1.0)\n[v1.3]  | `/r` option in `Regex`                              | `/U` (v1.1)\n[v1.3]  | `Set` behaviour                                     | `MapSet` data structure (v1.1)\n[v1.3]  | `String.valid_character?/1`                         | `String.valid?/1` (v1.0)\n[v1.3]  | `Task.find/2`                                       | Use direct message matching (v1.0)\n[v1.3]  | Non-map as 2nd argument in `URI.decode_query/2`     | Use a map (v1.0)\n[v1.2]  | `Dict` behaviour                                    | `Map` and `Keyword` (v1.0)\n[v1.1]  | `?\\xHEX`                                            | `0xHEX` (v1.0)\n[v1.1]  | `Access` protocol                                   | `Access` behaviour (v1.1)\n[v1.1]  | `as: true \\| false` in `alias/2` and `require/2`    | *None*\n\n[v1.1]: https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md#4-deprecations\n[v1.2]: https://github.com/elixir-lang/elixir/blob/v1.2/CHANGELOG.md#changelog-for-elixir-v12\n[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations\n[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations\n[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations\n[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations\n[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations\n[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations\n[v1.9]: https://github.com/elixir-lang/elixir/blob/v1.9/CHANGELOG.md#4-hard-deprecations\n[v1.10]: https://github.com/elixir-lang/elixir/blob/v1.10/CHANGELOG.md#4-hard-deprecations\n[v1.11]: https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#4-hard-deprecations\n[v1.12]: https://github.com/elixir-lang/elixir/blob/v1.12/CHANGELOG.md#4-hard-deprecations\n[v1.13]: https://github.com/elixir-lang/elixir/blob/v1.13/CHANGELOG.md#4-hard-deprecations\n[v1.14]: https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#4-hard-deprecations\n[v1.15]: https://github.com/elixir-lang/elixir/blob/v1.15/CHANGELOG.md#4-hard-deprecations\n[v1.16]: https://github.com/elixir-lang/elixir/blob/v1.16/CHANGELOG.md#4-hard-deprecations\n[v1.17]: https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md#4-hard-deprecations\n[v1.18]: https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md#4-hard-deprecations\n[v1.19]: https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md#4-hard-deprecations\n[v1.20]: https://github.com/elixir-lang/elixir/blob/v1.20/CHANGELOG.md#4-hard-deprecations\n[v1.21]: https://github.com/elixir-lang/elixir/blob/main/CHANGELOG.md#4-hard-deprecations\n","lib/elixir/pages/references/unicode-syntax.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Unicode syntax\n\nElixir supports Unicode throughout the language. This document is a complete reference of how\nElixir supports Unicode in its syntax.\n\nStrings (`\"olá\"`) and charlists (`'olá'`) support Unicode since Elixir v1.0. Strings are UTF-8 encoded. Charlists are lists of Unicode code points. In such cases, the contents are kept as written by developers, without any transformation.\n\nElixir also supports Unicode in variables, atoms, and calls since Elixir v1.5. The focus of this document is to provide a high-level introduction to how Elixir allows Unicode in its syntax. We also provide technical documentation describing how Elixir complies with the Unicode specification.\n\nTo check the Unicode version of your current Elixir installation, run `String.Unicode.version()`.\n\n## Introduction\n\nElixir allows Unicode characters in its variables, atoms, and calls. However, the Unicode characters must still obey the rules of the language syntax. In particular, variables and calls cannot start with an uppercase letter. From now on, we will refer to those terms as identifiers.\n\nThe characters allowed in identifiers are the ones specified by Unicode. Generally speaking, it is restricted to characters typically used by the writing system of human languages still in activity. In particular, it excludes symbols such as emojis, alternate numeric representations, musical notes, and the like.\n\nElixir imposes many restrictions on identifiers for security purposes. For example, the word \"josé\" can be written in two ways in Unicode: as the combination of the characters `j o s é` and as a combination of the characters `j o s e ́ `, where the accent is its own character. The former is called NFC form and the latter is the NFD form. Elixir normalizes all characters to be the in the NFC form.\n\nElixir also disallows mixed-scripts which are not explicitly separated by `_`. For example, it is not possible to name a variable `аdmin`, where `а` is in Cyrillic and the remaining characters are in Latin. Doing so will raise the following error:\n\n```text\n** (SyntaxError) invalid mixed-script identifier found: аdmin\n\nMixed-script identifiers are not supported for security reasons. 'аdmin' is made of the following scripts:\n\n  \\u0430 а {Cyrillic}\n  \\u0064 d {Latin}\n  \\u006D m {Latin}\n  \\u0069 i {Latin}\n  \\u006E n {Latin}\n\nMake sure all characters in the identifier resolve to a single script or a highly\nrestrictive script. See https://elixir.hexdocs.pm/unicode-syntax.html for more information.\n```\n\nFinally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.\n\nThat's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.\n\nFor the technical details, see the next sections that cover the technical Unicode requirements.\n\n## Unicode Standard Annex #31\n\nElixir conforms to the standards outlined in the [Unicode Standard Annex #31: Unicode Identifiers and Syntax](https://unicode.org/reports/tr31/), version 17.0.\n\n### R1. Default Identifiers\n\nThe general Elixir identifier rule is specified as:\n\n    <Identifier> := <Start> <Continue>* <Ending>?\n\nwhere `<Start>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> characters derived from the Unicode General Category of uppercase letters, lowercase letters, titlecase letters, modifier letters, other letters, letter numbers, plus `Other_ID_Start`, minus `Pattern_Syntax` and `Pattern_White_Space` code points\n>\n> In set notation: `[\\p{L}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\nand `<Continue>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> ID_Start characters, plus characters having the Unicode General Category of nonspacing marks, spacing combining marks, decimal number, connector punctuation, plus `Other_ID_Continue`, minus `Pattern_Syntax` and `Pattern_White_Space` code points.\n>\n> In set notation: `[\\p{ID_Start}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}\\p{Other_ID_Continue}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n`<Ending>` is an addition specific to Elixir that includes only the code points `?` (003F) and `!` (0021).\n\nThe spec also provides a `<Medial>` set, but Elixir does not include any character on this set. Therefore, the identifier rule has been simplified to consider this.\n\nElixir does not allow the use of ZWJ or ZWNJ in identifiers and therefore does not implement R1a. Bidirectional control characters are also not supported. R1b is guaranteed for backwards compatibility purposes.\n\n#### Atoms\n\nUnicode atoms in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Continue>` additionally includes the code point `@` (0040)\n\nNote atoms can also be quoted, which allows any characters, such as `:\"hello elixir\"`. All Elixir operators are also valid atoms, such as `:+`, `:@`, `:|>`, and others. The full description of valid atoms is available in the [\"Atoms\" section in the syntax reference](syntax-reference.md#atoms).\n\n#### Variables, local calls, and remote calls\n\nVariables in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Start>` additionally excludes Lu (letter uppercase) and Lt (letter titlecase) characters\n\nIn set notation: `[\\u{005F}\\p{Ll}\\p{Lm}\\p{Lo}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n#### Aliases\n\nAliases in Elixir only allow ASCII characters, starting in uppercase, and no punctuation characters.\n\n### R3. Pattern_White_Space and Pattern_Syntax Characters\n\nElixir supports only code points `\\t` (0009), `\\n` (000A), `\\r` (000D) and `\\s` (0020) as whitespace and therefore does not follow requirement R3. R3 requires a wider variety of whitespace and syntax characters to be supported.\n\n### R4. Equivalent Normalized Identifiers\n\nIdentifiers in Elixir are case sensitive.\n\nElixir normalizes all atoms and variables to NFC form. Quoted-atoms and strings can, however, be in any form and are not verified by the parser.\n\nIn other words, the atom `:josé` can only be written with the code points `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301`, but Elixir will rewrite it to the former (from Elixir 1.14). On the other hand, `:\"josé\"` may be written as `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301` and its form will be retained, since it is written between quotes.\n\nChoosing requirement R4 automatically excludes requirements R5, R6, and R7.\n\n## Unicode Technical Standard #39\n\nElixir conforms to the clauses outlined in the [Unicode Technical Standard #39](https://unicode.org/reports/tr39/) on Security, version 17.0.\n\n### C1. General Security Profile for Identifiers\n\nElixir will not allow tokenization of identifiers with codepoints in `\\p{Identifier_Status=Restricted}`, except for the outlined 'Additional normalizations' section below.\n\n> An implementation following the General Security Profile does not permit any characters in \\p{Identifier_Status=Restricted}, ...\n\nFor instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, is an uncommon codepoint and will trigger a warning.\n\n### C2. Confusable detection\n\nElixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.\n\nWe use the means described in Section 4, 'Confusable Detection', with one noted modification:\n\n> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.\n\nElixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).\n\n### C3. Mixed Script Detection\n\nElixir will not allow tokenization of mixed-script identifiers unless it is via chunks separated by an underscore, like `http_сервер`. We use the means described in Section 5.1, Mixed-Script Detection, to determine if script mixing is occurring, with the 'Additional Normalizations' documented in.\n\nExamples: Elixir allows an identifiers like `幻한`, even though it includes characters from multiple 'scripts', as Han characters may be mixed with Japanese and Korean, according to the rules from UTS 39 5.1. When mixing Latin and Japanese scripts, underscores are necessary, as in `:T_シャツ` (the Japanese word for 't-shirt' with an additional underscore separating the letter T).\n\nElixir does not allow code like `if аdmin, do: :ok, else: :err`, where the scriptset for the 'a' character is {Cyrillic} but all other characters have scriptsets of {Latin}. The scriptsets fail to resolve and a descriptive error is shown.\n\n### C4, C5 (inapplicable)\n\n'C4 - Restriction Level detection' conformance is not claimed and does not apply to identifiers in code; rather, it applies to classifying the level of safety of a given arbitrary string into one of 5 restriction levels.\n\n'C5 - Mixed number detection' conformance is inapplicable as Elixir does not support Unicode numbers.\n\n### Addition Normalizations\n\nAs of Elixir 1.14, some codepoints in `\\p{Identifier_Status=Restricted}` are *normalized* to other, unrestricted codepoints.\n\nThis is currently only applied to translate MICRO SIGN (`µ`) to Greek lowercase mu (`μ`).\n\nThe normalization avoids confusability and the mixed-script detection is modified to the extent that the normalized codepoint is given the union of scriptsets from both characters.\n\n  * For instance, in the example of MICRO => MU, MICRO was a 'Common'-script character - the same script given to the '_' underscore codepoint - and thus the normalized character's scriptset will be {Greek, Common}. 'Common' intersects with all non-empty scriptsets, and thus the normalized character can be used in tokens written in any script without causing script mixing.\n\n  * The code points normalized in this fashion are those that are in use in the community, and judged not likely to cause issues with unsafe script mixing. For instance, the MICRO or MU codepoint may be used in an atom or variable dealing with microseconds.\n","lib/elixir/pages/references/syntax-reference.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Syntax reference\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). This means the Elixir syntax is mostly uniform with a handful of \"syntax sugar\" constructs to reduce the noise in common Elixir idioms.\n\nThis document covers all of Elixir syntax constructs as a reference and then discuss their exact AST representation.\n\n## Reserved words\n\nThese are the reserved words in the Elixir language. They are detailed throughout this guide but summed up here for convenience:\n\n  * `true`, `false`, `nil` - used as atoms\n  * `when`, `and`, `or`, `not`, `in` - used as operators\n  * `fn` - used for anonymous function definitions\n  * `do`, `end`, `catch`, `rescue`, `after`, `else` - used in do-end blocks\n\n## Data types\n\n### Numbers\n\nIntegers (`1234`) and floats (`123.4`) in Elixir are represented as a sequence of digits that may be separated by underscore for readability purposes, such as `1_000_000`. Integers never contain a dot (`.`) in their representation. Floats contain a dot and at least one other digit after the dot. Floats also support the scientific notation, such as `123.4e10` or `123.4E10`.\n\n### Atoms\n\nUnquoted atoms start with a colon (`:`) which must be immediately followed by a Unicode letter or an underscore. The atom may continue using a sequence of Unicode letters, numbers, underscores, and `@`. Atoms may end in `!` or `?`. Valid unquoted atoms are: `:ok`, `:ISO8601`, and `:integer?`.\n\nIf the colon is immediately followed by a pair of double- or single-quotes surrounding the atom name, the atom is considered quoted. In contrast with an unquoted atom, this one can be made of any Unicode character (not only letters), such as `:'🌢 Elixir'`, `:\"++olá++\"`, and `:\"123\"`.\n\nQuoted and unquoted atoms with the same name are considered equivalent, so `:atom`, `:\"atom\"`, and `:'atom'` represent the same atom. The only catch is that the compiler will warn when quotes are used in atoms that do not need to be quoted.\n\nAll operators in Elixir are also valid atoms. Valid examples are `:foo`, `:FOO`, `:foo_42`, `:foo@bar`, and `:++`. Invalid examples are `:@foo` (`@` is not allowed at start), `:123` (numbers are not allowed at start), and `:(*)` (not a valid operator).\n\n`true`, `false`, and `nil` are reserved words that are represented by the atoms `:true`, `:false` and `:nil` respectively.\n\nTo learn more about all Unicode characters allowed in atom, see the [Unicode syntax](unicode-syntax.md) document.\n\n### Strings\n\nSingle-line strings in Elixir are written between double-quotes, such as `\"foo\"`. Any double-quote inside the string must be escaped with `\\ `. Strings support Unicode characters and are stored as UTF-8 encoded binaries.\n\nMulti-line strings in Elixir are called heredocs. They are written with three double-quotes, and can have unescaped quotes within them. The resulting string will end with a newline. The indentation of the last `\"\"\"` is used to strip indentation from the inner string. For example:\n\n```elixir\niex> test = \"\"\"\n...>     this\n...>     is\n...>     a\n...>     test\n...> \"\"\"\n\"    this\\n    is\\n    a\\n    test\\n\"\niex> test = \"\"\"\n...>     This\n...>     Is\n...>     A\n...>     Test\n...>     \"\"\"\n\"This\\nIs\\nA\\nTest\\n\"\n```\n\nStrings are always represented as themselves in the AST.\n\n### Charlists\n\nCharlists are lists of non-negative integers where each integer represents a Unicode code point.\n\n```elixir\niex(6)> 'abc' === [97, 98, 99]\ntrue\n```\n\nCharlists are written in single-quotes, such as `'foo'`. Any single-quote inside the string must be escaped with `\\ `.\nMulti-line charlists are written with three single-quotes (`'''`), the same way multi-line strings are.\nHowever, this syntax is deprecated in favor of the charlist sigil `~c`.\n\nCharlists are always represented as themselves in the AST.\n\nFor more in-depth information, please read the \"Charlists\" section in the `List` module.\n\n### Lists, tuples and binaries\n\nData structures such as lists, tuples, and binaries are marked respectively by the delimiters `[...]`, `{...}`, and `<<...>>`. Each element is separated by comma. A trailing comma is also allowed, such as in `[1, 2, 3,]`.\n\n### Maps and keyword lists\n\nMaps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{\"hello\" => 1, 2 => \"world\"}`.\n\nBoth keyword lists (list of two-element tuples where the first element is an atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: \"world\"}` is equivalent to `%{:hello => \"world\"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.\n\n### Structs\n\nStructs built on the map syntax by passing the struct name between `%` and `{`. For example, `%User{...}`.\n\n## Expressions\n\n### Variables\n\nVariables in Elixir must start with an underscore or a Unicode letter that is not in uppercase or titlecase. The variable may continue using a sequence of Unicode letters, numbers, and underscores. Variables may end in `?` or `!`. To learn more about all Unicode characters allowed in variables, see the [Unicode syntax](unicode-syntax.md) document.\n\n[Elixir's naming conventions](naming-conventions.md) recommend variables to be in `snake_case` format.\n\n### Non-qualified calls (local calls)\n\nNon-qualified calls, such as `add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments.\n\nParentheses are required for zero-arity calls (i.e. calls without arguments), to avoid ambiguity with variables. If parentheses are used, they must immediately follow the function name *without spaces*. For example, `add (1, 2)` is a syntax error, since `(1, 2)` is treated as an invalid block which is attempted to be given as a single argument to `add`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Operators\n\nAs many programming languages, Elixir also support operators as non-qualified calls with their precedence and associativity rules. Constructs such as `=`, `when`, `&` and `@` are simply treated as operators. See [the Operators page](operators.md) for a full reference.\n\n### Qualified calls (remote calls)\n\nQualified calls, such as `Math.add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments. Qualified calls also support operators, such as `Kernel.+(1, 2)`. Elixir also allows the function name to be written between double- or single-quotes, allowing any character in between the quotes, such as `Math.\"++add++\"(1, 2)`.\n\nSimilar to non-qualified calls, parentheses have different meaning for zero-arity calls (i.e. calls without arguments). If parentheses are used, such as `mod.fun()`, it means a function call. If parenthesis are skipped, such as `map.field`, it means accessing a field of a map.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Aliases\n\nAliases are constructs that expand to atoms at compile-time. The alias `String` expands to the atom `:\"Elixir.String\"`. Aliases must start with an ASCII uppercase character which may be followed by any ASCII letter, number, or underscore. Non-ASCII characters are not supported in aliases.\n\nMultiple aliases can be joined with `.`, such as `MyApp.String`, and it expands to the atom `:\"Elixir.MyApp.String\"`. The dot is effectively part of the name but it can also be used for composition. If you define `alias MyApp.Example, as: Example` in your code, then `Example` will always expand to `:\"Elixir.MyApp.Example\"` and `Example.String` will expand to `:\"Elixir.MyApp.Example.String\"`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend aliases to be in `CamelCase` format.\n\n### Module attributes\n\nModule attributes are module-specific storage and are written as the composition of the unary operator `@` with variables and local calls. For example, to write to a module attribute named `foo`, use `@foo \"value\"`, and use `@foo` to read from it. Given module attributes are written using existing constructs, they follow the same rules above defined for operators, variables, and local calls.\n\n### Blocks\n\nBlocks are multiple Elixir expressions separated by newlines or semi-colons. A new block may be created at any moment by using parentheses.\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is used to establish a relationship between left and right, commonly referred as clauses. The left side may have zero, one, or more arguments; the right side is zero, one, or more expressions separated by new line. The `->` may appear one or more times between one of the following terminators: `do`-`end`, `fn`-`end` or `(`-`)`. When `->` is used, only other clauses are allowed between those terminators. Mixing clauses and regular expressions is invalid syntax.\n\nIt is seen on `case` and `cond` constructs between `do` and `end`:\n\n```elixir\ncase 1 do\n  2 -> 3\n  4 -> 5\nend\n\ncond do\n  true -> false\nend\n```\n\nSeen in typespecs between `(` and `)`:\n\n```elixir\n(integer(), boolean() -> integer())\n```\n\nIt is also used between `fn` and `end` for building anonymous functions:\n\n```elixir\nfn\n  x, y -> x + y\nend\n```\n\n### Sigils\n\nSigils start with `~` and are followed by one lowercase letter or by one or more uppercase letters, immediately followed by one of the following pairs:\n\n  * `(` and `)`\n  * `{` and `}`\n  * `[` and `]`\n  * `<` and `>`\n  * `\"` and `\"`\n  * `'` and `'`\n  * `|` and `|`\n  * `/` and `/`\n\nAfter closing the pair, zero or more ASCII letters and digits can be given as a modifier. Sigils are expressed as non-qualified calls prefixed with `sigil_` where the first argument is the sigil contents as a string and the second argument is a list of integers as modifiers:\n\nIf the sigil letter is in uppercase, no interpolation is allowed in the sigil, otherwise its contents may be dynamic. Compare the results of the sigils below for more information:\n\n```elixir\n~s/f#{\"o\"}o/\n~S/f#{\"o\"}o/\n```\n\nSigils are useful to encode text with their own escaping rules, such as regular expressions, datetimes, and others.\n\n## The Elixir AST\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). Elixir's AST is a regular Elixir data structure composed of the following elements:\n\n  * atoms - such as `:foo`\n  * integers - such as `42`\n  * floats - such as `13.1`\n  * strings - such as `\"hello\"`\n  * lists - such as `[1, 2, 3]`\n  * tuples with two elements - such as `{\"hello\", :world}`\n  * tuples with three elements, representing calls or variables, as explained next\n\nThe building block of Elixir's AST is a call, such as:\n\n```elixir\nsum(1, 2, 3)\n```\n\nwhich is represented as a tuple with three elements:\n\n```elixir\n{:sum, meta, [1, 2, 3]}\n```\n\nthe first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.\n\nWe can retrieve the AST for any Elixir expression by calling `quote`:\n\n```elixir\nquote do\n  sum()\nend\n#=> {:sum, [], []}\n```\n\nVariables are also represented using a tuple with three elements and a combination of lists and atoms, for example:\n\n```elixir\nquote do\n  sum\nend\n#=> {:sum, [], Elixir}\n```\n\nYou can see that variables are also represented with a tuple, except the third element is an atom expressing the variable context.\n\nOver the course of this section, we will explore many Elixir syntax constructs alongside their AST representations.\n\n### Operators\n\nOperators are treated as non-qualified calls:\n\n```elixir\nquote do\n  1 + 2\nend\n#=> {:+, [], [1, 2]}\n```\n\nNote that `.` is also an operator. Remote calls use the dot in the AST with two arguments, where the second argument is always an atom:\n\n```elixir\nquote do\n  foo.bar(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}\n```\n\nCalling anonymous functions uses the dot in the AST with a single argument, mirroring the fact the function name is \"missing\" from right side of the dot:\n\n```elixir\nquote do\n  foo.(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}\n```\n\n### Aliases\n\nAliases are represented by an `__aliases__` call with each segment separated by a dot as an argument:\n\n```elixir\nquote do\n  Foo.Bar.Baz\nend\n#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}\n\nquote do\n  __MODULE__.Bar.Baz\nend\n#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}\n```\n\nAll arguments, except the first, are guaranteed to be atoms.\n\n### Data structures\n\nRemember that lists are literals, so they are represented as themselves in the AST:\n\n```elixir\nquote do\n  [1, 2, 3]\nend\n#=> [1, 2, 3]\n```\n\nTuples have their own representation, except for two-element tuples, which are represented as themselves:\n\n```elixir\nquote do\n  {1, 2}\nend\n#=> {1, 2}\n\nquote do\n  {1, 2, 3}\nend\n#=> {:{}, [], [1, 2, 3]}\n```\n\nBinaries have a representation similar to tuples, except they are tagged with `:<<>>` instead of `:{}`:\n\n```elixir\nquote do\n  <<1, 2, 3>>\nend\n#=> {:<<>>, [], [1, 2, 3]}\n```\n\nThe same applies to maps, where pairs are treated as a list of tuples with two elements:\n\n```elixir\nquote do\n  %{1 => 2, 3 => 4}\nend\n#=> {:%{}, [], [{1, 2}, {3, 4}]}\n```\n\n### Blocks\n\nBlocks are represented as a `__block__` call with each line as a separate argument:\n\n```elixir\nquote do\n  1\n  2\n  3\nend\n#=> {:__block__, [], [1, 2, 3]}\n\nquote do 1; 2; 3; end\n#=> {:__block__, [], [1, 2, 3]}\n```\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is represented similar to operators except that they are always part of a list, its left side represents a list of arguments and the right side is an expression.\n\nFor example, in `case` and `cond`:\n\n```elixir\nquote do\n  case 1 do\n    2 -> 3\n    4 -> 5\n  end\nend\n#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}\n\nquote do\n  cond do\n    true -> false\n  end\nend\n#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}\n```\n\nBetween `(` and `)`:\n\n```elixir\nquote do\n  (1, 2 -> 3\n   4, 5 -> 6)\nend\n#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]\n```\n\nBetween `fn` and `end`:\n\n```elixir\nquote do\n  fn\n    1, 2 -> 3\n    4, 5 -> 6\n  end\nend\n#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}\n```\n\n### Qualified tuples\n\nQualified tuples (`foo.{bar, baz}`) are represented by a `{:., [], [expr, :{}]}` call, where the `expr` represents the left hand side of the dot, and the arguments represent the elements inside the curly braces. This is used in Elixir to provide multi aliases:\n\n```elixir\nquote do\n  Foo.{Bar, Baz}\nend\n#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}\n```\n\n### `do`-`end` blocks\n\nElixir's `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:\n\n```elixir\nif true do\n  this\nelse\n  that\nend\n```\n\nis the same as:\n\n```elixir\nif(true, do: (this), else: (that))\n```\n\nWhile the construct above does not require custom nodes in Elixir's AST, they are restricted only to certain keywords, listed next:\n\n  * `after`\n  * `catch`\n  * `else`\n  * `rescue`\n\nYou will find them in constructs such as `receive`, `try`, and others. You can also find more examples in [the Optional Syntax chapter](../getting-started/optional-syntax.md).\n","lib/elixir/pages/references/typespecs.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Typespecs reference\n\n> #### Typespecs are not set-theoretic types {: .warning}\n>\n> Elixir is in the process of implementing its\n> [own type system](./gradual-set-theoretic-types.md) based on set-theoretic types.\n> Typespecs, which are described in the following document, are a distinct notation\n> for declaring types and specifications based on Erlang.\n> Typespecs may be phased out as the set-theoretic type effort moves forward.\n\nElixir is a dynamically typed language, and as such, type specifications are never used by the compiler to optimize or modify code. Still, using type specifications is useful because:\n\n  * they provide documentation (for example, tools such as [`ExDoc`](https://ex-doc.hexdocs.pm/) show type specifications in the documentation)\n  * they're used by tools such as [Dialyzer](`:dialyzer`), that can analyze code with typespecs to find type inconsistencies and possible bugs\n\nType specifications (most often referred to as *typespecs*) are defined in different contexts using the following attributes:\n\n  * `@type`\n  * `@opaque`\n  * `@typep`\n  * `@spec`\n  * `@callback`\n  * `@macrocallback`\n\nIn addition, you can use `@typedoc` to document a custom `@type` definition.\n\nSee the \"User-defined types\" and \"Defining a specification\" sub-sections below for more information on defining types and typespecs.\n\n## A simple example\n\n    defmodule StringHelpers do\n      @typedoc \"A word from the dictionary\"\n      @type word() :: String.t()\n\n      @spec long_word?(word()) :: boolean()\n      def long_word?(word) when is_binary(word) do\n        String.length(word) > 8\n      end\n    end\n\nIn the example above:\n\n  * We declare a new type (`word()`) that is equivalent to the string type (`String.t()`).\n\n  * We describe the type using a `@typedoc`, which will be included in the generated documentation.\n\n  * We specify that the `long_word?/1` function takes an argument of type `word()` and\n    returns a boolean (`boolean()`), that is, either `true` or `false`.\n\n## Types and their syntax\n\nThe syntax Elixir provides for type specifications is similar to [the one in Erlang](https://www.erlang.org/doc/reference_manual/typespec.html). Most of the built-in types provided in Erlang (for example, `pid()`) are expressed in the same way: `pid()` (or simply `pid`). Parameterized types (such as `list(integer)`) are supported as well and so are remote types (such as [`Enum.t()`](`t:Enum.t/0`)). Integers and atom literals are allowed as types (for example, `1`, `:atom`, or `false`). All other types are built out of unions of predefined types. Some types can also be declared using their syntactical notation, such as `[type]` for lists, `{type1, type2, ...}` for tuples and `<<_ * _>>` for binaries.\n\nThe notation to represent the union of types is the pipe `|`. For example, the typespec `type :: atom() | pid() | tuple()` creates a type `type` that can be either an `atom`, a `pid`, or a `tuple`. This is usually called a [sum type](https://en.wikipedia.org/wiki/Tagged_union) in other languages\n\n> #### Differences with set-theoretic types {: .warning}\n>\n> While they do share some similarities, the types below do not map one-to-one\n> to the new types from the set-theoretic type system.\n>\n> For example, there is no plan to support subsets of the `integer()` type such\n> as positive, ranges or literals.\n>\n> Furthermore, set-theoretic types support the full range of set operations,\n> including intersections and negations.\n\n### Basic types\n\n    type ::\n          any()                     # the top type, the set of all terms\n          | none()                  # the bottom type, contains no terms\n          | atom()\n          | map()                   # any map\n          | pid()                   # process identifier\n          | port()                  # port identifier\n          | reference()\n          | tuple()                 # tuple of any size\n\n                                    ## Numbers\n          | float()\n          | integer()\n          | neg_integer()           # ..., -3, -2, -1\n          | non_neg_integer()       # 0, 1, 2, 3, ...\n          | pos_integer()           # 1, 2, 3, ...\n\n                                                                          ## Lists\n          | list(type)                                                    # proper list ([]-terminated)\n          | nonempty_list(type)                                           # non-empty proper list\n          | maybe_improper_list(content_type, termination_type)           # proper or improper list\n          | nonempty_improper_list(content_type, termination_type)        # improper list\n          | nonempty_maybe_improper_list(content_type, termination_type)  # non-empty proper or improper list\n\n          | Literals                # Described in section \"Literals\"\n          | BuiltIn                 # Described in section \"Built-in types\"\n          | Remotes                 # Described in section \"Remote types\"\n          | UserDefined             # Described in section \"User-defined types\"\n\n### Literals\n\nThe following literals are also supported in typespecs:\n\n    type ::                               ## Atoms\n          :atom                           # atoms: :foo, :bar, ...\n          | true | false | nil            # special atom literals\n\n                                          ## Bitstrings\n          | <<>>                          # empty bitstring\n          | <<_::size>>                   # size is 0 or a positive integer\n          | <<_::_*unit>>                 # unit is an integer from 1 to 256\n          | <<_::size, _::_*unit>>\n\n                                          ## (Anonymous) Functions\n          | (-> type)                     # zero-arity, returns type\n          | (type1, type2 -> type)        # two-arity, returns type\n          | (... -> type)                 # any arity, returns type\n\n                                          ## Integers\n          | 1                             # integer\n          | 1..10                         # integer from 1 to 10\n\n                                          ## Lists\n          | [type]                        # list with any number of type elements\n          | []                            # empty list\n          | [...]                         # shorthand for nonempty_list(any())\n          | [type, ...]                   # shorthand for nonempty_list(type)\n          | [key: value_type]             # keyword list with optional key :key of value_type\n\n                                                  ## Maps\n          | %{}                                   # empty map\n          | %{key: value_type}                    # map with required key :key of value_type\n          | %{key_type => value_type}             # map with required pairs of key_type and value_type\n          | %{required(key_type) => value_type}   # map with required pairs of key_type and value_type\n          | %{optional(key_type) => value_type}   # map with optional pairs of key_type and value_type\n          | %SomeStruct{}                         # struct with all fields of any type\n          | %SomeStruct{key: value_type}          # struct with required key :key of value_type\n\n                                          ## Tuples\n          | {}                            # empty tuple\n          | {:ok, type}                   # two-element tuple with an atom and any type\n\n### Built-in types\n\nThe following types are also provided by Elixir as shortcuts on top of the basic and literal types described above.\n\nBuilt-in type           | Defined as\n:---------------------- | :---------\n`term()`                | `any()`\n`arity()`               | `0..255`\n`as_boolean(t)`         | `t`\n`binary()`              | `<<_::_*8>>`\n`nonempty_binary()`     | `<<_::8, _::_*8>>`\n`bitstring()`           | `<<_::_*1>>`\n`nonempty_bitstring()`  | `<<_::1, _::_*1>>`\n`boolean()`             | `true` \\| `false`\n`byte()`                | `0..255`\n`char()`                | `0..0x10FFFF`\n`charlist()`            | `[char()]`\n`nonempty_charlist()`   | `[char(), ...]`\n`fun()`                 | `(... -> any)`\n`function()`            | `fun()`\n`identifier()`          | `pid()` \\| `port()` \\| `reference()`\n`iodata()`              | `iolist()` \\| `binary()`\n`iolist()`              | `maybe_improper_list(byte() \\| binary() \\| iolist(), binary() \\| [])`\n`keyword()`             | `[{atom(), any()}]`\n`keyword(t)`            | `[{atom(), t}]`\n`list()`                | `[any()]`\n`nonempty_list()`       | `nonempty_list(any())`\n`maybe_improper_list()` | `maybe_improper_list(any(), any())`\n`nonempty_maybe_improper_list()` | `nonempty_maybe_improper_list(any(), any())`\n`mfa()`                 | `{module(), atom(), arity()}`\n`module()`              | `atom()`\n`no_return()`           | `none()`\n`node()`                | `atom()`\n`number()`              | `integer()` \\| `float()`\n`struct()`              | `%{:__struct__ => atom(), optional(atom()) => any()}`\n`timeout()`             | `:infinity` \\| `non_neg_integer()`\n\n`as_boolean(t)` exists to signal users that the given value will be treated as a boolean, where `nil` and `false` will be evaluated as `false` and everything else is `true`. For example, `Enum.filter/2` has the following specification: `filter(t, (element -> as_boolean(term))) :: list`.\n\n### Remote types\n\nAny module is also able to define its own types and the modules in Elixir are no exception. For example, the `Range` module defines a `t/0` type that represents a range: this type can be referred to as `t:Range.t/0`. In a similar fashion, a string is `t:String.t/0`, and so on.\n\n### Maps\n\nThe key types in maps are allowed to overlap, and if they do, the leftmost key takes precedence.\nA map value does not belong to this type if it contains a key that is not in the allowed map keys.\n\nIf you want to denote that keys that were not previously defined in the map are allowed,\nit is common to end a map type with `optional(any) => any`.\n\nNote that the syntactic representation of `map()` is `%{optional(any) => any}`, not `%{}`. The notation `%{}` specifies the singleton type for the empty map.\n\n### Keyword Lists\n\nBeyond `keyword()` and `keyword(t)`, it can be helpful to compose a spec for an expected keyword list.\nFor example:\n\n```elixir\n@type option :: {:name, String.t} | {:max, pos_integer} | {:min, pos_integer}\n@type options :: [option()]\n```\n\nThis makes it clear that only these options are allowed, none are required, and order does not matter.\n\nIt also allows composition with existing types.\nFor example:\n\n```elixir\n@type option :: {:my_option, String.t()} | GenServer.option()\n\n@spec start_link([option()]) :: GenServer.on_start()\ndef start_link(opts) do\n  {my_opts, gen_server_opts} = Keyword.split(opts, [:my_option])\n  GenServer.start_link(__MODULE__, my_opts, gen_server_opts)\nend\n```\n\nThe following spec syntaxes are equivalent:\n\n```elixir\n@type options :: [{:name, String.t} | {:max, pos_integer} | {:min, pos_integer}]\n\n@type options :: [name: String.t, max: pos_integer, min: pos_integer]\n```\n\n### User-defined types\n\nThe `@type`, `@typep`, and `@opaque` module attributes can be used to define new types:\n\n    @type type_name :: type\n    @typep type_name :: type\n    @opaque type_name :: type\n\nA type defined with `@typep` is private. An opaque type, defined with `@opaque` is a type where the internal structure of the type will not be visible, but the type is still public.\n\nTypes can be parameterized by defining variables as parameters; these variables can then be used to define the type.\n\n    @type dict(key, value) :: [{key, value}]\n\n## Defining a specification\n\nA specification for a function can be defined as follows:\n\n    @spec function_name(type1, type2) :: return_type\n\nGuards can be used to restrict type variables given as arguments to the function.\n\n    @spec function(arg) :: [arg] when arg: atom\n\nIf you want to specify more than one variable, you separate them by a comma.\n\n    @spec function(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer\n\nType variables with no restriction can also be defined using `var`.\n\n    @spec function(arg) :: [arg] when arg: var\n\nThis guard notation only works with `@spec`, `@callback`, and `@macrocallback`.\n\nYou can also name your arguments in a typespec using `arg_name :: arg_type` syntax. This is particularly useful in documentation as a way to differentiate multiple arguments of the same type (or multiple elements of the same type in a type definition):\n\n    @spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer\n    @type color :: {red :: integer, green :: integer, blue :: integer}\n\nSpecifications can be overloaded, just like ordinary functions.\n\n    @spec function(integer) :: atom\n    @spec function(atom) :: integer\n\n## Behaviours\n\nBehaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*).\n\nA behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This \"interface\" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a \"server\" process will likely want to implement from the specific parts such as the actions that this server process has to perform.\n\nSay we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).\n\nWe can create a `Parser` behaviour:\n\n```elixir\ndefmodule Parser do\n  @doc \"\"\"\n  Parses a string.\n  \"\"\"\n  @callback parse(String.t) :: {:ok, term} | {:error, atom}\n\n  @doc \"\"\"\n  Lists all supported file extensions.\n  \"\"\"\n  @callback extensions() :: [String.t]\nend\n```\n\nAs seen in the example above, defining a callback is a matter of defining a specification for that callback, made of:\n\n  * the callback name (`parse` or `extensions` in the example)\n  * the arguments that the callback must accept (`String.t`)\n  * the *expected* type of the callback return value\n\nModules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above.\n\n### Implementing behaviours\n\nImplementing a behaviour is straightforward:\n\n```elixir\ndefmodule JSONParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some json \" <> str} # ... parse JSON\n\n  @impl Parser\n  def extensions, do: [\".json\"]\nend\n```\n\n```elixir\ndefmodule CSVParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some csv \" <> str} # ... parse CSV\n\n  @impl Parser\n  def extensions, do: [\".csv\"]\nend\n```\n\nIf a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.\n\nFurthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.\n\n```elixir\ndefmodule BADParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse, do: {:ok, \"something bad\"}\n\n  @impl Parser\n  def extensions, do: [\"bad\"]\nend\n```\n\nThis code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.\nYou can read more about `@impl` in the [module documentation](`Module#module-impl`).\n\n### Using behaviours\n\nBehaviours are useful because you can pass modules around as arguments and you can then *call back* to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:\n\n```elixir\n@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}\ndef parse_path(filename, parsers) do\n  with {:ok, ext} <- parse_extension(filename),\n       {:ok, parser} <- find_parser(ext, parsers),\n       {:ok, contents} <- File.read(filename) do\n    parser.parse(contents)\n  end\nend\n\ndefp parse_extension(filename) do\n  case Path.extname(filename) do\n    \"\" -> {:error, :no_extension}\n    ext -> {:ok, ext}\n  end\nend\n\ndefp find_parser(ext, parsers) do\n  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do\n    {:ok, parser}\n  else\n    {:error, :no_matching_parser}\n  end\nend\n```\n\nYou could also invoke any parser directly: `CSVParser.parse(...)`.\n\nNote you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.\n\n### Optional callbacks\n\nOptional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.\n\n> ### Unloaded modules {: .warning}\n>\n> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.\n\nOptional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:\n\n    defmodule MyBehaviour do\n      @callback vital_fun() :: any\n      @callback non_vital_fun() :: any\n      @macrocallback non_vital_macro(arg :: any) :: Macro.t\n      @optional_callbacks non_vital_fun: 0, non_vital_macro: 1\n    end\n\nOne example of optional callback in Elixir's standard library is `c:GenServer.format_status/1`.\n\n### Inspecting behaviours\n\nThe `@callback` and `@optional_callbacks` attributes are used to create a `behaviour_info/1` function available on the defining module. This function can be used to retrieve the callbacks and optional callbacks defined by that module.\n\nFor example, for the `MyBehaviour` module defined in \"Optional callbacks\" above:\n\n    MyBehaviour.behaviour_info(:callbacks)\n    #=> [vital_fun: 0, \"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n    MyBehaviour.behaviour_info(:optional_callbacks)\n    #=> [\"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n\nWhen using `iex`, the `IEx.Helpers.b/1` helper is also available.\n\n## Pitfalls\n\nThere are some known pitfalls when using typespecs, they are documented next.\n\n## The `string()` type\n\nElixir discourages the use of the `string()` type. The `string()` type refers to Erlang strings, which are known as \"charlists\" in Elixir. They do not refer to Elixir strings, which are UTF-8 encoded binaries. To avoid confusion, if you attempt to use the type `string()`, Elixir will emit a warning. You should use `charlist()`, `nonempty_charlist()`, `binary()` or `String.t()` accordingly, or any of the several literal representations for these types.\n\nNote that `String.t()` and `binary()` are equivalent to analysis tools. Although, for those reading the documentation, `String.t()` implies it is a UTF-8 encoded binary.\n\n## Functions which raise an error\n\nTypespecs do not need to indicate that a function can raise an error; any function can fail any time if given invalid input.\nIn the past, the Elixir standard library sometimes used `no_return()` to indicate this, but these usages have been removed.\n\nThe `no_return()` type also should not be used for functions which do return but whose purpose is a \"side effect\", such as `IO.puts/1`.\nIn these cases, the expected return type is `:ok`.\n\nInstead, `no_return()` should be used as the return type for functions which can never return a value.\nThis includes functions which loop forever calling `receive`, or which exist specifically to raise an error, or which shut down the VM.\n",".cursorrules (elixir-engineer-guidelines-cursorrules-prompt-file.mdc)":"---\ndescription: \"Cursor rules for Elixir development with engineer guidelines.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: \nElixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n\nWhere:\n\ntype: One of the following:\n\nscope (optional): A noun describing a section of the codebase (e.g., fluxcd, deployment).\n\ndescription: A brief summary of the change in present tense.\n\nbody (optional): A more detailed explanation of the change.\n\nfooter (optional): One or more footers in the following format:\n"},"files":{"lib/elixir/pages/references/library-guidelines.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Library guidelines\n\nThis document outlines general guidelines for those writing and publishing\nElixir libraries meant to be consumed by other developers.\n\n## Getting started\n\nYou can create a new Elixir library by running the `mix new` command:\n\n    $ mix new my_library\n\nThe project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.\n\nEvery project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.\n\nThe `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).\n\n## Publishing\n\nWriting code is only the first of many steps to publish a package. We strongly recommend developers to:\n\n  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).\n\n  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.\n\n  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.\n\n  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.\n\n  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports \"extra pages\", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.\n\n  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.\n\nProjects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).\n\n## Dependency handling\n\nWhen your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.\n\nKeep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).\n\nOn the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.\n\nIf you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.\n\n### Dependency Version Requirements\n\nWhen depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `\"~> x.y\"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.\n\nThe exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `\"~> 0.1.2\"` is a better default.\n\nA common mistake is to use a dependency in the format of `\"~> x.y.z\"` to express \"a version greater than `x.y.z`\". For example, if you are depending on `\"~> 1.2\"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `\"~> 1.2.1\"` to express that dependency, you are preventing users from upgrading to `\"1.3.0\"` or higher! Instead of `\"~> 1.2.1\"`, you should use `\"~> 1.2 and >= 1.2.1\"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.\n","lib/elixir/pages/references/sbom.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Software Bill of Materials\n\nA Software Bill of Materials (SBoM) is a structured inventory of the components that make up a software system. This guide explains what SBoMs are, why they matter, and how to generate them for Elixir projects.\n\n## What is an SBoM?\n\nAn SBoM is a formal, machine-readable record of all components in a piece of software. Think of it as a detailed ingredient list for your application. A typical SBoM includes:\n\n  * **Dependencies**: all libraries and packages your project uses\n  * **Versions**: the exact version of each component\n  * **Source locations**: where each component was obtained (Hex, GitHub, etc.)\n  * **Checksums**: cryptographic hashes to verify integrity\n  * **Licensing information**: the license under which each component is distributed\n\nTwo widely adopted standards exist for SBoM formats:\n\n  * [CycloneDX](https://cyclonedx.org/): a lightweight standard designed for security contexts\n  * [SPDX](https://spdx.dev/): a more comprehensive standard originally focused on licensing\n\nBoth formats are machine-readable (JSON, XML) and designed to be consumed by automated tooling.\n\n> #### SBoM is an inventory, not a certification {: .info}\n>\n> An SBoM does not claim that software is secure, compliant, or free of vulnerabilities.\n> It simply provides a detailed inventory that enables further analysis. Security and\n> compliance assessments are performed by separate tools that consume the SBoM.\n\n## Why generate SBoMs?\n\nThere are three main reasons to generate SBoMs for your projects.\n\n### Vulnerability analysis\n\nWhen a security vulnerability (CVE) is discovered in a library, you need to quickly determine if your projects are affected. SBoMs make this possible by providing a complete inventory of your dependencies.\n\nTools like [OWASP Dependency-Track](https://dependencytrack.org/) continuously monitor your SBoMs against vulnerability databases. When a new CVE is published, you get notified if any of your projects use the affected component.\n\nWithout an SBoM, answering \"are we affected by CVE-2024-XXXXX?\" means manually checking each project, which is time-consuming and error-prone.\n\n### Regulatory requirements\n\nSBoMs are required by some regulations and procurement policies:\n\n  * **US Executive Order 14028** (2021) requires SBoMs for certain software supplied to the U.S. federal government, particularly for designated critical software\n  * **EU Cyber Resilience Act** introduces requirements for component inventories (commonly fulfilled using SBoMs) for products with digital elements placed on the EU market\n  * **Safety-critical industries** (medical devices, automotive, aerospace) often require detailed component inventories as part of certification\n\nCustomers and partners may also request SBoMs as part of their own compliance efforts.\n\n### License compliance\n\nEvery dependency in your project comes with a license. An SBoM provides a starting point for license review by listing the declared license for each package. This helps you:\n\n  * Get an overview of licenses in your dependency tree\n  * Flag packages that may need closer review\n  * Support due diligence for acquisitions, audits, or legal review\n\nNote that package-level license information (as provided by mix_sbom) reflects what the package declares, not necessarily all licenses present in its source files. For thorough license compliance, file-level scanning tools like ORT provide deeper analysis.\n\n## Generating SBoMs with mix_sbom\n\n[mix_sbom](https://github.com/erlef/mix_sbom) is an EEF project that generates CycloneDX SBoMs for Elixir projects.\n\n### Installation\n\nThere are several ways to install mix_sbom:\n\n  * **As a project dependency**: add `sbom` to your `mix.exs`\n  * **As a global escript**: run `mix escript.install hex sbom` (requires Elixir 1.19.4+)\n  * **As a standalone binary**: download from the [releases page](https://github.com/erlef/mix_sbom/releases)\n\nThe standalone binary is useful for CI environments or when you don't want to modify your project's dependencies. It requires no local Elixir or Erlang installation.\n\n### Basic usage\n\nTo generate an SBoM for your project using the standalone binary:\n\n```console\n$ mix_sbom cyclonedx /path/to/your/project\n```\n\nThis creates a `bom.cdx.json` file in CycloneDX format containing your project's complete dependency tree.\n\n### Common options\n\nThe most useful options are:\n\n  * `-o, --output PATH`: specify the output file (default: `bom.cdx.json`)\n  * `-t, --format FORMAT`: output format (`json`, `xml`, or `protobuf`)\n  * `-s, --schema VERSION`: CycloneDX schema version\n\nFor example, to generate an XML format SBoM:\n\n```console\n$ mix_sbom cyclonedx --format xml --output sbom.xml /path/to/project\n```\n\n## CI integration\n\nFor automated SBoM generation, mix_sbom provides a GitHub Action:\n\n```yaml\nname: Generate SBoM\non:\n  release:\n    types: [published]\n\njobs:\n  sbom:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: erlef/mix_sbom@v0\n        with:\n          path: \".\"\n          format: \"json\"\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sbom\n          path: bom.cdx.json\n```\n\nThis workflow generates an SBoM whenever you publish a release and uploads it as a build artifact. See the [action's documentation](https://github.com/erlef/mix_sbom) for additional options.\n\n## Deeper analysis with ORT\n\nmix_sbom provides package-level license information based on what each dependency declares. However, some compliance workflows require file-level scanning. A package might declare an MIT license but contain individual files under different licenses, or include vendored code with its own licensing terms.\n\nThe [OSS Review Toolkit (ORT)](https://oss-review-toolkit.org/) addresses this by scanning actual source files for license headers and copyright notices. ORT supports Mix projects and provides:\n\n  * **File-level license detection**: scans source code for license texts and SPDX identifiers\n  * **Copyright holder identification**: extracts copyright notices from files\n  * **Policy enforcement**: define rules for allowed and denied licenses\n  * **Multi-ecosystem support**: analyze projects that span multiple package managers\n\nFor organizations with strict compliance requirements, ORT complements mix_sbom by providing the deeper analysis needed for thorough license audits.\n\nSee the [ORT Mix plugin documentation](https://oss-review-toolkit.org/ort/docs/plugins/package-managers/Mix) for details.\n\n## Next steps\n\n  * [CycloneDX Specification](https://cyclonedx.org/specification/overview/): learn more about the SBoM format\n  * [OWASP Dependency-Track](https://dependencytrack.org/): continuous SBoM analysis platform\n  * [mix_sbom documentation](https://sbom.hexdocs.pm): full documentation and advanced options\n","lib/elixir/pages/references/naming-conventions.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Naming conventions\n\nThis document is a reference of the naming conventions in Elixir, from casing to punctuation characters.\n\nThe naming convention is, by definition, a subset of the Elixir syntax. A convention aims to\nfollow and set best practices for language and the community. If instead you want a complete reference into the Elixir syntax, beyond its conventions, see [the Syntax reference](syntax-reference.md).\n\n## Casing\n\nElixir developers must use `snake_case` when defining variables, function names, module attributes, and the like:\n\n    some_map = %{this_is_a_key: \"and a value\"}\n    is_map(some_map)\n\nAliases, commonly used as module names, are an exception as they must be capitalized and written in `CamelCase`, like `OptionParser`. For aliases, capital letters are kept in acronyms, like `ExUnit.CaptureIO` or `Mix.SCM`.\n\nAtoms can be written either in `:snake_case` or `:CamelCase`, although the convention is to use the snake case version throughout Elixir.\n\nGenerally speaking, filenames follow the `snake_case` convention of the module they define. For example, `MyApp` should be defined inside the `my_app.ex` file. However, this is only a convention. At the end of the day any filename can be used as they do not affect the compiled code in any way.\n\n## Underscore (`_foo`)\n\nElixir relies on underscores in different situations.\n\nFor example, a value that is not meant to be used must be assigned to `_` or to a variable starting with underscore:\n\n    iex> {:ok, _contents} = File.read(\"README.md\")\n\nFunction names may also start with an underscore. Such functions are never imported by default:\n\n    iex> defmodule Example do\n    ...>   def _wont_be_imported do\n    ...>     :oops\n    ...>   end\n    ...> end\n\n    iex> import Example\n    iex> _wont_be_imported()\n    ** (CompileError) iex:1: undefined function _wont_be_imported/0\n\nDue to this property, Elixir relies on functions starting with underscore to attach compile-time metadata to modules. Such functions are most often in the `__foo__` format. For example, every module in Elixir has an [`__info__/1`](`c:Module.__info__/1`) function:\n\n    iex> String.__info__(:functions)\n    [at: 2, capitalize: 1, chunk: 2, ...]\n\nElixir also includes five special forms that follow the double underscore format: `__CALLER__/0`, `__DIR__/0`, `__ENV__/0`and `__MODULE__/0` retrieve compile-time information about the current environment, while `__STACKTRACE__/0` retrieves the stacktrace for the current exception.\n\n## Trailing bang (`foo!`)\n\nA trailing bang (exclamation mark) signifies a function or macro where failure cases raise an exception. They most often exist as a \"raising variant\" of a function that returns `:ok`/`:error` tuples (or `nil`).\n\nOne example is `File.read/1` and `File.read!/1`. `File.read/1` will return a success or failure tuple, whereas `File.read!/1` will return a plain value or else raise an exception:\n\n    iex> File.read(\"file.txt\")\n    {:ok, \"file contents\"}\n    iex> File.read(\"no_such_file.txt\")\n    {:error, :enoent}\n\n    iex> File.read!(\"file.txt\")\n    \"file contents\"\n    iex> File.read!(\"no_such_file.txt\")\n    ** (File.Error) could not read file no_such_file.txt: no such file or directory\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n    case File.read(file) do\n      {:ok, body} -> # do something with the `body`\n      {:error, reason} -> # handle the error caused by `reason`\n    end\n\nHowever, if you expect the outcome to always be successful (for instance, if you expect the file always to exist), the bang variation can be more convenient and will raise a more helpful error message (than a failed pattern match) on failure.\n\nWhen thinking about failure cases, we are often thinking about semantic errors related to the operation being performed, such as failing to open a file or trying to fetch key from a map. Errors that come from invalid argument types, or similar, must always raise regardless if the function has a bang or not. In such cases, the exception is often an `ArgumentError` or a detailed `FunctionClauseError`:\n\n    iex(1)> File.read(123)\n    ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1\n\n        The following arguments were given to IO.chardata_to_string/1:\n\n            # 1\n            123\n\n        Attempted function clauses (showing 2 out of 2):\n\n            def chardata_to_string(string) when is_binary(string)\n            def chardata_to_string(list) when is_list(list)\n\nMore examples of paired functions: `Base.decode16/2` and `Base.decode16!/2`, `File.cwd/0` and `File.cwd!/0`. In some situations, you may have bang functions without a non-bang counterpart. They also imply the possibility of errors, such as: `Protocol.assert_protocol!/1` and `PartitionSupervisor.resize!/2`. This can be useful if you foresee the possibility of adding a non-raising variant in the future.\n\n## Trailing question mark (`foo?`)\n\nFunctions that return a boolean are named with a trailing question mark.\n\nExamples: `Keyword.keyword?/1`, `Mix.debug?/0`, `String.contains?/2`\n\nHowever, functions that return booleans and are valid in guards follow another convention, described next.\n\n## `is_` prefix (`is_foo`)\n\nType checks and other boolean checks that are allowed in guard clauses are named with an `is_` prefix.\n\nExamples: `Integer.is_even/1`, `is_list/1`\n\nThese 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. Type checks that are not valid in guard clauses do not follow this convention, such as `Keyword.keyword?/1`.\n\nA trailing question mark should not be used in combination with the `is_` prefix.\n\n## Special names\n\nSome names have specific meaning in Elixir. We detail those cases below.\n\n### length and size\n\nWhen you see `size` in a function name, it means the operation runs in constant time (also written as \"O(1) time\") because the size is stored alongside the data structure.\n\nExamples: `map_size/1`, `tuple_size/1`\n\nWhen you see `length`, the operation runs in linear time (\"O(n) time\") because the entire data structure has to be traversed.\n\nExamples: `length/1`, `String.length/1`\n\nIn other words, functions using the word \"size\" in its name will take the same amount of time whether the data structure is tiny or huge. Conversely, functions having \"length\" in its name will take more time as the data structure grows in size.\n\n### get, fetch, fetch!\n\nWhen you see the functions `get`, `fetch`, and `fetch!` for key-value data structures, you can expect the following behaviours:\n\n  * `get` returns a default value (which itself defaults to `nil`) if the key is not present, or returns the requested value.\n  * `fetch` returns `:error` if the key is not present, or returns `{:ok, value}` if it is.\n  * `fetch!` *raises* if the key is not present, or returns the requested value.\n\nExamples: `Map.get/2`, `Map.fetch/2`, `Map.fetch!/2`, `Keyword.get/2`, `Keyword.fetch/2`, `Keyword.fetch!/2`\n\n### compare\n\nThe function `compare/2` should return `:lt` if the first term is less than the second, `:eq` if the two\nterms compare as equivalent, or `:gt` if the first term is greater than the second.\n\nExamples: `DateTime.compare/2`\n\nNote that this specific convention is important due to the expectations of `Enum.sort/2`\n","lib/elixir/pages/references/operators.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Operators reference\n\nThis document is a complete reference of operators in Elixir, how they are parsed, how they can be defined, and how they can be overridden.\n\n## General operators\n\nElixir provides the following built-in operators:\n\n  * [`+`](`+/1`) and [`-`](`-/1`) - unary positive/negative\n  * [`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), and [`/`](`//2`) - basic arithmetic operations\n  * [`++`](`++/2`) and [`--`](`--/2`) - list concatenation and subtraction\n  * [`and`](`and/2`) and [`&&`](`&&/2`) - strict and relaxed boolean \"and\"\n  * [`or`](`or/2`) and [`||`](`||/2`) - strict and relaxed boolean \"or\"\n  * [`not`](`not/1`) and [`!`](`!/1`) - strict and relaxed boolean \"not\"\n  * [`in`](`in/2`) and [`not in`](`in/2`) - membership\n  * [`@`](`@/1`) - module attribute\n  * [`..`](`../0`), [`..`](`../2`), and [`..//`](`..///3`) - range creation\n  * [`<>`](`<>/2`) - binary concatenation\n  * [`|>`](`|>/2`) - pipeline\n  * [`=~`](`=~/2`) - text-based match\n\nMany of those can be used in guards. Consult the [list of allowed guard functions and operators](patterns-and-guards.md#list-of-allowed-functions-and-operators).\n\nAdditionally, there are a few other operators that Elixir parses but doesn't actually use.\nSee [Custom and overridden operators](#custom-and-overridden-operators) below for a list and for guidelines about their use.\n\nSome other operators are special forms and cannot be overridden:\n\n  * [`^`](`^/1`) - pin operator\n  * [`.`](`./2`) - dot operator\n  * [`=`](`=/2`) - match operator\n  * [`&`](`&/1`) - capture operator\n  * [`::`](`::/2`) - type operator\n\nFinally, these operators appear in the precedence table below but are only meaningful within certain constructs:\n\n  * `=>` - see [`%{}`](`%{}/1`)\n  * `when` - see [Guards](patterns-and-guards.md#guards)\n  * `<-` - see [`for`](`for/1`) and [`with`](`with/1`)\n  * `\\\\` - see [Default arguments](`Kernel#def/2-default-arguments`)\n\n## Comparison operators\n\nElixir provides the following built-in comparison operators (all of which can be used in guards):\n\n  * [`==`](`==/2`) - equal to\n  * [`===`](`===/2`) - strictly equal to\n  * [`!=`](`!=/2`) - not equal to\n  * [`!==`](`!==/2`) - strictly not equal to\n  * [`<`](`</2`) - less-than\n  * [`>`](`>/2`) - greater-than\n  * [`<=`](`<=/2`) - less-than or equal to\n  * [`>=`](`>=/2`) - greater-than or equal to\n\nThe only difference between [`==`](`==/2`) and [`===`](`===/2`) is that [`===`](`===/2`) is strict when it comes to comparing integers and floats:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 === 1.0\nfalse\n```\n\n[`!=`](`!=/2`) and [`!==`](`!==/2`) act as the negation of [`==`](`==/2`) and [`===`](`===/2`), respectively.\n\n## Operator precedence and associativity\n\nThe following is a list of all operators that Elixir is capable of parsing, ordered from higher to lower precedence, alongside their associativity:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`@`                                            | Unary\n`.`                                            | Left\n`+` `-` `!` `^` `not`                          | Unary\n`**`                                           | Left\n`*` `/`                                        | Left\n`+` `-`                                        | Left\n`++` `--` `+++` `---` `..` `<>`                | Right\n`//` (valid only inside `..//`)                | Right\n`in` `not in`                                  | Left\n`\\|>` `<<<` `>>>` `<<~` `~>>` `<~` `~>` `<~>`  | Left\n`<` `>` `<=` `>=`                              | Left\n`==` `!=` `=~` `===` `!==`                     | Left\n`&&` `&&&` `and`                               | Left\n`\\|\\|` `\\|\\|\\|` `or`                           | Left\n`=`                                            | Right\n`&`, `...`                                     | Unary\n`\\|`                                           | Right\n`::`                                           | Right\n`when`                                         | Right\n`<-` `\\\\`                                      | Left\n`=>` (valid only inside `%{}`)                 | None\n\nElixir also has two ternary operators:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`first..last//step`                            | Right\n`%{map \\| key => value, ...}`                  | None\n\n> #### Deprecated operator precedence {: .info}\n>\n> Elixir parses `not left in right` as `not(left in right)` and `!left in right` as `!(left in right)`, which mismatches the precedence table above, but such behaviour is deprecated and emits a warning. Both constructs must be written as `left not in right` instead. In future major versions, the parser will match the table above.\n\n## Custom and overridden operators\n\nElixir is capable of parsing a predefined set of operators. It's not possible to define new operators (as supported by some languages). However, not all operators that Elixir can parse are *used* by Elixir: for example, `+` and `||` are used by Elixir for addition and boolean *or*, but `<~>` is not used (but valid).\n\nTo define an operator, you can use the usual `def*` constructs (`def`, `defp`, `defmacro`, and so on) but with a syntax similar to how the operator is used:\n\n```elixir\ndefmodule MyOperators do\n  # We define ~> to return the maximum of the given two numbers,\n  # and <~ to return the minimum.\n\n  def a ~> b, do: max(a, b)\n  def a <~ b, do: min(a, b)\nend\n```\n\nTo use the newly defined operators, you **have to** import the module that defines them:\n\n```elixir\niex> import MyOperators\niex> 1 ~> 2\n2\niex> 1 <~ 2\n1\n```\n\nThe following is a table of all the operators that Elixir is capable of parsing, but that are not used by default:\n\n  * `|||`\n  * `&&&`\n  * `<<<`\n  * `>>>`\n  * `<<~`\n  * `~>>`\n  * `<~`\n  * `~>`\n  * `<~>`\n  * `+++`\n  * `---`\n  * `...`\n\nThe following operators are used by the `Bitwise` module when imported: [`&&&`](`Bitwise.&&&/2`), [`<<<`](`Bitwise.<<</2`), [`>>>`](`Bitwise.>>>/2`), and [`|||`](`Bitwise.|||/2`). See the `Bitwise` documentation for more information.\n\nNote that the Elixir community generally discourages custom operators. They can be hard to read and even more to understand, as they don't have a descriptive name like functions do. That said, some specific cases or custom domain specific languages (DSLs) may justify these practices.\n\nIt is also possible to replace predefined operators, such as `+`, but doing so is extremely discouraged.\n","lib/elixir/pages/references/patterns-and-guards.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Patterns and guards\n\nElixir provides pattern matching, which allows us to assert on the shape or extract values from data structures. Patterns are often augmented with guards, which give developers the ability to perform more complex checks, albeit limited.\n\nThis document provides a complete reference on patterns and guards, their semantics, where they are allowed, and how to extend them.\n\n## Patterns\n\nPatterns in Elixir are made of variables, literals, and data structure specific syntax. One of the most used constructs to perform pattern matching is the match operator ([`=`](`=/2`)):\n\n```iex\niex> x = 1\n1\niex> 1 = x\n1\n```\n\nIn the example above, `x` starts without a value and has `1` assigned to it. Then, we compare the value of `x` to the literal `1`, which succeeds as they are both `1`.\n\nMatching `x` against 2 would raise:\n\n```iex\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nPatterns are not bidirectional. If you have a variable `y` that was never assigned to (often called an unbound variable) and you write `1 = y`, an error will be raised:\n\n```iex\niex> 1 = y\n** (CompileError) iex:2: undefined variable \"y\"\n```\n\nIn other words, patterns are allowed only on the left side of `=`. The right side of `=` follows the regular evaluation semantics of the language.\n\nNow let's cover the pattern matching rules for each construct and then for each relevant data types.\n\n### Variables\n\nVariables in patterns are always assigned to:\n\n```iex\niex> x = 1\n1\niex> x = 2\n2\niex> x\n2\n```\n\nIn other words, Elixir supports rebinding. In case you don't want the value of a variable to change, you can use the pin operator (`^`):\n\n```iex\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nIf the same variable appears multiple times in the same pattern, then all of them must be bound to the same value:\n\n```iex\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nHowever, a variable cannot be defined through itself in the same pattern. This includes cases where the variable appears on both sides of a nested match operator:\n\n```elixir\n{:ok, x} = {x, :ok}\n%{a: value} = %{b: value}\n```\n\nSuch patterns are rejected as cyclic variable definitions. You can rewrite them by matching once and then using guards or separate comparisons for the additional constraints.\n\nThe underscore variable (`_`) has a special meaning as it can never be bound to any value. It is especially useful when you don't care about certain value in a pattern:\n\n```iex\niex> {_, integer} = {:not_important, 1}\n{:not_important, 1}\niex> integer\n1\niex> _\n** (CompileError) iex:3: invalid use of _\n```\n\nA pinned value represents the value itself and not its – even if syntactically equal – pattern. The right hand side is compared to be equal to the pinned value:\n\n```iex\niex> x = %{}\n%{}\niex> {:ok, %{}} = {:ok, %{a: 13}}\n{:ok, %{a: 13}}\niex> {:ok, ^x} = {:ok, %{a: 13}}\n** (MatchError) no match of right hand side value: {:ok, %{a: 13}}\n    (stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6\n    iex:2: (file)\n```\n\n### Literals (numbers and atoms)\n\nAtoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:\n\n```iex\niex> :atom = :atom\n:atom\niex> :atom = :another_atom\n** (MatchError) no match of right hand side value: :another_atom\n```\n\nSimilar rule applies to numbers. Finally, note that numbers in patterns perform strict comparison. In other words, integers to do not match floats:\n\n```iex\niex> 1 = 1.0\n** (MatchError) no match of right hand side value: 1.0\n```\n\n### Tuples\n\nTuples may appear in patterns using the curly brackets syntax (`{}`). A tuple in a pattern will match only tuples of the same size, where each individual tuple element must also match:\n\n```iex\niex> {:ok, integer} = {:ok, 13}\n{:ok, 13}\n\n# won't match due to different size\niex> {:ok, integer} = {:ok, 11, 13}\n** (MatchError) no match of right hand side value: {:ok, 11, 13}\n\n# won't match due to mismatch on first element\niex> {:ok, binary} = {:error, :enoent}\n** (MatchError) no match of right hand side value: {:error, :enoent}\n```\n\n### Lists\n\nLists may appear in patterns using the square brackets syntax (`[]`). A list in a pattern will match only lists of the same size, where each individual list element must also match:\n\n```iex\niex> [:ok, integer] = [:ok, 13]\n[:ok, 13]\n\n# won't match due to different size\niex> [:ok, integer] = [:ok, 11, 13]\n** (MatchError) no match of right hand side value: [:ok, 11, 13]\n\n# won't match due to mismatch on first element\niex> [:ok, binary] = [:error, :enoent]\n** (MatchError) no match of right hand side value: [:error, :enoent]\n```\n\nOpposite to tuples, lists also allow matching on non-empty lists by using the `[head | tail]` notation, which matches on the `head` and `tail` of a list:\n\n```iex\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nMultiple elements may prefix the `| tail` construct:\n\n```iex\niex> [first, second | tail] = [1, 2, 3]\n[1, 2, 3]\niex> tail\n[3]\n```\n\nNote `[head | tail]` does not match empty lists:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nGiven charlists are represented as a list of integers, one can also perform prefix matches on charlists using the list concatenation operator ([`++`](`++/2`)):\n\n```elixir\niex> ~c\"hello \" ++ world = ~c\"hello world\"\n~c\"hello world\"\niex> world\n~c\"world\"\n```\n\nWhich is equivalent to matching on `[?h, ?e, ?l, ?l, ?o, ?\\s | world]`. Suffix matches (`hello ++ ~c\" world\"`) are not valid patterns.\n\n### Maps\n\nMaps may appear in patterns using the percentage sign followed by the curly brackets syntax (`%{}`). Opposite to lists and tuples, maps perform a subset match. This means a map pattern will match any other map that has at least all of the keys in the pattern.\n\nHere is an example where all keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\"}\n%{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nHere is when a subset of the keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\", age: 23}\n%{age: 23, name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf a key in the pattern is not available in the map, then they won't match:\n\n```iex\niex> %{name: name, age: age} = %{name: \"meg\"}\n** (MatchError) no match of right hand side value: %{name: \"meg\"}\n```\n\nNote that the empty map will match all maps, which is a contrast to tuples and lists, where an empty tuple or an empty list will only match empty tuples and empty lists respectively:\n\n```iex\niex> %{} = %{name: \"meg\"}\n%{name: \"meg\"}\n```\n\nFinally, note map keys in patterns must always be literals or previously bound variables matched with the pin operator.\n\n### Structs\n\nStructs may appear in patterns using the percentage sign, the struct module name or a variable followed by the curly brackets syntax (`%{}`).\n\nGiven the following struct:\n\n```elixir\ndefmodule User do\n  defstruct [:name]\nend\n```\n\nHere is an example where all keys match:\n\n```iex\niex> %User{name: name} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf an unknown key is given, the compiler will raise an error:\n\n```iex\niex> %User{type: type} = %User{name: \"meg\"}\n** (CompileError) iex: unknown key :type for struct User\n```\n\nThe struct name can be extracted when putting a variable instead of a module name:\n\n```elixir\niex> %struct_name{} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> struct_name\nUser\n```\n\n### Binaries\n\nBinaries may appear in patterns using the double less-than/greater-than syntax ([`<<>>`](`<<>>/1`)). A binary in a pattern can match multiple segments at the same time, each with different type, size, and unit:\n\n```iex\niex> <<val::unit(8)-size(2)-integer>> = <<123, 56>>\n\"{8\"\niex> val\n31544\n```\n\nSee the documentation for [`<<>>`](`<<>>/1`) for a complete definition of pattern matching for binaries.\n\nFinally, remember that strings in Elixir are UTF-8 encoded binaries. This means that, similar to charlists, prefix matches on strings are also possible with the binary concatenation operator ([`<>`](`<>/2`)):\n\n```elixir\niex> \"hello \" <> world = \"hello world\"\n\"hello world\"\niex> world\n\"world\"\n```\n\nSuffix matches (`hello <> \" world\"`) are not valid patterns.\n\n## Guards\n\nGuards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed, such as function definitions, case clauses, and others.\n\nNot all expressions are allowed in guard clauses, but only a handful of them. This is a deliberate choice. This way, Elixir (through Erlang) ensures that all guards are predictable (no mutations or other side-effects) and they can be optimized and performed efficiently.\n\n### List of allowed functions and operators\n\nYou can find the built-in list of guards [in the `Kernel` module](`Kernel#guards`). Here is an overview:\n\n  * comparison operators ([`==`](`==/2`), [`!=`](`!=/2`), [`===`](`===/2`), [`!==`](`!==/2`),\n    [`<`](`</2`), [`<=`](`<=/2`), [`>`](`>/2`), [`>=`](`>=/2`)), [`max`](`max/2`), [`min`](`min/2`)\n  * strictly boolean operators ([`and`](`and/2`), [`or`](`or/2`), [`not`](`not/1`)). Note [`&&`](`&&/2`), [`||`](`||/2`), and [`!`](`!/1`) sibling operators are **not allowed** as they're not *strictly* boolean - meaning they don't require arguments to be booleans\n  * arithmetic unary operators ([`+`](`+/1`), [`-`](`-/1`))\n  * arithmetic binary operators ([`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), [`/`](`//2`))\n  * [`in`](`in/2`) and [`not in`](`in/2`) operators (as long as the right-hand side is a list or a range)\n  * \"type-check\" functions (`is_list/1`, `is_number/1`, and the like)\n  * functions that work on built-in data types (`abs/1`, `hd/1`, `map_size/1`, and others)\n  * the `map.field` syntax\n\nThe module `Bitwise` also includes a handful of [Erlang bitwise operations as guards](Bitwise.html#guards).\n\nMacros constructed out of any combination of the above guards are also valid guards - for example, `Integer.is_even/1`. For more information, see the \"Custom patterns and guards expressions\" section shown below.\n\n### Why guards\n\nLet's see an example of a guard used in a function clause:\n\n```elixir\ndef empty_map?(map) when map_size(map) == 0, do: true\ndef empty_map?(map) when is_map(map), do: false\n```\n\nGuards start with the `when` operator, followed by a guard expression. The clause will be executed if and only if the guard expression returns `true`. Multiple boolean conditions can be combined with the [`and`](`and/2`) and [`or`](`or/2`) operators.\n\nWriting the `empty_map?/1` function by only using pattern matching would not be possible (as pattern matching on `%{}` would match *any* map, not only the empty ones).\n\n### Non-passing guards\n\nA function clause will be executed if and only if its guard expression evaluates to `true`. If any other value is returned, the function clause will be skipped. In particular, guards have no concept of \"truthy\" or \"falsy\".\n\nFor example, imagine a function that checks that the head of a list is not `nil`:\n\n```elixir\ndef not_nil_head?([head | _]) when head, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> false\n```\n\nEven though the head of the list is not `nil`, the first clause for `not_nil_head?/1` fails because the expression does not evaluate to `true`, but to `\"some_value\"`, therefore triggering the second clause which returns `false`. To make the guard behave correctly, you must ensure that the guard evaluates to `true`, like so:\n\n```elixir\ndef not_nil_head?([head | _]) when head != nil, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> true\n```\n\n### Errors in guards\n\nIn guards, when functions would normally raise exceptions, they cause the guard to fail instead.\n\nFor example, the `tuple_size/1` function only works with tuples. If we use it with anything else, an argument error is raised:\n\n```elixir\niex> tuple_size(\"hello\")\n** (ArgumentError) argument error\n```\n\nHowever, when used in guards, the corresponding clause will fail to match instead of raising an error:\n\n```elixir\niex> case \"hello\" do\n...>   something when tuple_size(something) == 2 ->\n...>     :worked\n...>   _anything_else ->\n...>     :failed\n...> end\n:failed\n```\n\nIn many cases, we can take advantage of this. In the code above, we used `tuple_size/1` to both check that the given value is a tuple *and* check its size (instead of using `is_tuple(something) and tuple_size(something) == 2`).\n\nHowever, if your guard has multiple conditions, such as checking for tuples or maps, it is best to call type-check functions like `is_tuple/1` before `tuple_size/1`, otherwise the whole guard will fail if a tuple is not given. Alternatively, your function clause can use multiple guards as shown in the following section.\n\n### Multiple guards in the same clause\n\nThere exists an additional way to simplify a chain of `or` expressions in guards: Elixir supports writing \"multiple guards\" in the same clause. The following code:\n\n```elixir\ndef categorize_number(term) when is_integer(term) or is_float(term) or is_nil(term),\n  do: :maybe_number\ndef categorize_number(_other),\n  do: :something_else\n```\n\ncan be alternatively written as:\n\n```elixir\ndef categorize_number(term)\n    when is_integer(term)\n    when is_float(term)\n    when is_nil(term) do\n  :maybe_number\nend\n\ndef categorize_number(_other) do\n  :something_else\nend\n```\n\nIf each guard expression always returns a boolean, the two forms are equivalent. However, recall that if any function call in a guard raises an exception, the entire guard fails. To illustrate this, the following function will not detect empty tuples:\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and tuple_size/1 will not be evaluated\n  def empty?(val) when map_size(val) == 0 or tuple_size(val) == 0, do: true\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> false # true was expected!\n```\n\nThis could be corrected by ensuring that no exception is raised, either via type checks like `is_map(val) and map_size(val) == 0`, or by using multiple guards, so that if an exception causes one guard to fail, the next one is evaluated.\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and the second guard will be evaluated\n  def empty?(val)\n      when map_size(val) == 0\n      when tuple_size(val) == 0,\n      do: true\n\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> true\n```\n\n## Where patterns and guards can be used\n\nIn the examples above, we have used the match operator ([`=`](`=/2`)) and function clauses to showcase patterns and guards respectively. Here is the list of the built-in constructs in Elixir that support patterns and guards.\n\n  * `match?/2`:\n\n    ```elixir\n    match?({:ok, value} when value > 0, {:ok, 13})\n    ```\n\n  * function clauses:\n\n    ```elixir\n    def type(term) when is_integer(term), do: :integer\n    def type(term) when is_float(term), do: :float\n    ```\n\n  * [`case`](`case/2`) expressions:\n\n    ```elixir\n    case x do\n      1 -> :one\n      2 -> :two\n      n when is_integer(n) and n > 2 -> :larger_than_two\n    end\n    ```\n\n  * anonymous functions (`fn/1`):\n\n    ```elixir\n    larger_than_two? = fn\n      n when is_integer(n) and n > 2 -> true\n      n when is_integer(n) -> false\n    end\n    ```\n\n  * [`for`](`for/1`) and [`with`](`with/1`) support patterns and guards on the left side of `<-`:\n\n    ```elixir\n    for x when x >= 0 <- [1, -2, 3, -4], do: x\n    ```\n\n    `with` also supports the `else` keyword, which supports patterns matching and guards.\n\n  * [`try`](`try/1`) supports patterns and guards on `catch` and `else`\n\n  * [`receive`](`receive/1`) supports patterns and guards to match on the received messages.\n\n  * custom guards can also be defined with `defguard/1` and `defguardp/1`. A custom guard can only be defined based on existing guards.\n\nNote that the match operator ([`=`](`=/2`)) does *not* support guards:\n\n```elixir\n{:ok, binary} = File.read(\"some/file\")\n```\n\n## Custom patterns and guards expressions\n\nOnly the constructs listed in this page are allowed in patterns and guards. However, we can take advantage of macros to write custom patterns 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 boils down to a combination of the constructs above.\n\nFor example, the `Record` module in Elixir provides a series of macros to be used in patterns and guards that allows tuples to have named fields during compilation.\n\nFor defining your own guards, Elixir even provides conveniences in `defguard` and `defguardp`. Let's look at a quick case study: we want to check whether an argument is an even or an odd integer. With pattern matching this is impossible because there is an infinite number of integers, and therefore we can't pattern match on every single one of them. Therefore we must use guards. We will just focus on checking for even numbers since checking for the odd ones is almost identical.\n\nSuch a guard would look like this:\n\n```elixir\ndef my_function(number) when is_integer(number) and rem(number, 2) == 0 do\n  # do stuff\nend\n```\n\nIt would be repetitive to write every time we need this check. Instead, you can use `defguard/1` and `defguardp/1` to create guard macros. Here's an example how:\n\n```elixir\ndefmodule MyInteger do\n  defguard is_even(term) when is_integer(term) and rem(term, 2) == 0\nend\n```\n\nand then:\n\n```elixir\nimport MyInteger, only: [is_even: 1]\n\ndef my_function(number) when is_even(number) do\n  # do stuff\nend\n```\n\nWhile it's possible to create custom guards with macros, it's recommended to define them using `defguard/1` and `defguardp/1` which perform additional compile-time checks.\n","lib/elixir/pages/references/gradual-set-theoretic-types.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Gradual set-theoretic types\n\nElixir is in the process of incorporating set-theoretic types into the compiler. This document outlines the current stage of our implementation for this Elixir version. Elixir's type system is:\n\n  * **sound** - the inferred and assigned by the type system align with the behaviour of the program\n\n  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. However, instead of simply discarding all typing information, Elixir's `dynamic()` type works as a range. For example, if you write `dynamic(integer() or binary())`, Elixir's type system will still emit violations if none of those types are accepted. Furthermore, in the absence of `dynamic()`, Elixir's type system behaves as a static one\n\n  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)\n\nThe current milestone aims to infer types from existing programs and use them for type checking, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. User provided type signatures are planned for future releases. The underlying principles, theory, and roadmap of our work have been outlined in [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).\n\n## A gentle introduction\n\nTypes in Elixir are written using the type named followed by parentheses, such as `integer()` or `list(integer())`.\n\nThe basic types are:\n\n```elixir\natom()\nbinary()\nbitstring()\nempty_list()\ninteger()\nfloat()\nfunction()\nmap()\nnon_empty_list(elem_type, tail_type)\npid()\nport()\nreference()\ntuple()\n```\n\nMany of the types above can also be written more precisely. We will discuss their syntax in the next sections, but here are two examples:\n\n  * While `atom()` represents all atoms, the atom `:ok` can also be represented in the type system as `:ok`\n\n  * While `tuple()` represents all tuples, you can specify the type of a two-element tuple where the first element is the atom `:ok` and the second is an integer as `{:ok, integer()}`\n\nThere are also three special types: `none()` (represents an empty set), `term()` (represents all types), `dynamic()` (represents a range of the given types).\n\nGiven the types are set-theoretic, we can compose them using unions (`or`), intersections (`and`), and negations (`not`). For example, to say a function returns either atoms or integers, one could write: `atom() or integer()`.\n\nIntersections will find the elements in common between the operands. For example, `atom() and integer()`, which in this case is the empty set `none()`. You can combine intersections and negations to perform difference, for example, to say that a function expects all atoms, except `nil` (which is an atom), you could write: `atom() and not nil`.\n\nYou can find a complete reference in the [set-theoretic types cheatsheet](../cheatsheets/types-cheat.cheatmd).\n\n## The syntax of data types\n\nIn this section we will cover the syntax of all data types. At the moment, developers will interact with those types mostly through compiler warnings and diagnostics.\n\n### Broad types\n\nThese types are broad in that they cannot represent individual elements, only the whole set. For example, the numbers `1` and `42` are both represented by the type `integer()`.\n\nThey are: `binary()`, `bitstring()`, `integer()`, `float()`, `pid()`, `port()`, `reference()`.\n\nThe `binary()` type is a subtype of the less frequently used `bitstring()` type, as binaries are bitstrings where the number of bits is divisible by 8.\n\n### Atoms\n\nYou can represent all atoms as `atom()`. You can also represent each individual atom using their literal syntax. For instance, the atom `:foo` and `:hello_world` are also valid (distinct) types.\n\n`nil`, `true`, and `false` are also atoms and can be written as is. `boolean()` is a convenience type alias that represents `true or false`.\n\n### Tuples\n\nYou can represent all tuples as `tuple()`. Tuples may also be written using the curly brackets syntax, such as `{:ok, binary()}`.\n\nYou may use `...` at the end of the tuple to imply the overall size of the tuple is unknown. For example, the following tuple has at least two elements: `{:ok, binary(), ...}`.\n\n### Lists\n\nYou can represent all _proper_ lists as `list()`, which also includes the empty list.\n\nYou can also specify the type of the list element as argument. For example, `list(integer())` represents the values `[]` and `[1, 2, 3]`, but not `[1, \"two\", 3]`.\n\nInternally, Elixir represents the type `list(a)` as the union two distinct types, `empty_list()` and `non_empty_list(a)`. In other words, `list(integer())` is equivalent to `empty_list() or non_empty_list(integer())`.\n\n#### Improper lists\n\nWhile most developers will simply use `list(a)`, the type system can express all different representations of lists in Elixirby passing a second argument to `non_empty_list`, which represents the type of the tail.\n\nA proper list is one where the tail is the empty list itself. The type `non_empty_list(integer())` is equivalent to `non_empty_list(integer(), empty_list())`.\n\nIf the `tail_type` is anything but a list, then we have an improper list. For example, the value `[1, 2 | 3]` would have the type `non_empty_list(integer(), integer())`.\n\nIf you pass a list type as the tail, then the list type is merged into the element type. For example, `non_empty_list(integer(), list(binary()))` is the same as `non_empty_list(integer() or binary(), empty_list())`.\n\n### Maps\n\nYou can represent all maps as `map()`.\n\nMaps may also be written using their literal syntax:\n\n```elixir\n%{name: binary(), age: integer()}\n```\n\nwhich outlines a map with exactly two keys, `:name` and `:age`, and values of type `binary()` and `integer()` respectively. We say the map above is \"closed\": it only supports the keys explicitly defined. We can also mark a map as \"open\", by including `...` as its first element:\n\n```elixir\n%{..., name: binary(), age: integer()}\n```\n\nThe type above says the keys `:name` and `:age` must exist, with their respective types, but other keys may be present. The `map()` type is the same as `%{...}`. For the empty map, you may write `%{}`, although we recommend using `empty_map()` for clarity.\n\n#### Optional keys\n\nA key may be marked as optional using the `if_set/1` operation on its value type:\n\n```elixir\n%{name: binary(), age: if_set(integer())}\n```\n\nis a map that certainly has the `:name` key but it may have the `:age` key (and if it has such key, its value type is `integer()`).\n\nYou can also use `not_set()` to denote a key cannot be present:\n\n```elixir\n%{..., age: not_set()}\n```\n\nThe type above says the map may have any key, except the `:age` one. This is, for instance, the type returned by `Map.delete(map, :age)`.\n\n#### Domain types\n\nIn the examples above, all map keys were atoms, but we can also use other types as map keys. For example:\n\n```elixir\n# Closed map\n%{binary() or atom() => integer()}\n\n# Open map\n%{..., binary() or atom() => integer()}\n```\n\nCurrently, the type system only tracks the top of each individual type as the domain keys. For example, if you say:\n\n```elixir\n%{list(integer()) => integer(), list(binary()) => binary()}\n```\n\nThat's the same as specifying all lists:\n\n```elixir\n%{list() => integer() or binary()}\n```\n\nThe supported domain keys are `atom()`, `bitstring()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, and `tuple()`. In the case of maps, the `bitstring()` domain stores exclusively keys which are not binary. The ones which are `binary()` are stored under the `binary()` domain.\n\nFurthermore, it is important to note that domain keys are, by definition, optional. Whenever you have a `%{integer() => integer()}`and you try to fetch a key, we must assume the key may not exist (after all, it is not possible to store all integers as map keys as they are infinite).\n\n#### Mixed keys\n\nIt is also possible to mix domain and atom keys. For example, the following map says that all atom keys are of type `binary()`, except the `:root` key, which has type `integer()`:\n\n```elixir\n# Closed map\n%{atom() => binary(), root: integer()}\n\n# Open map\n%{..., atom() => binary(), root: integer()}\n```\n\nThe order of the keys is of increasing precision. `:root` is more precise than `atom()`, therefore it comes later. This mirrors the runtime semantics of maps, where duplicate keys override the value of earlier ones.\n\n### Functions\n\nYou can represent all functions as `function()`.  However, in practice, most functions are represented as arrows. For example, a function that receives an integer and return boolean would be written as `(integer() -> boolean())`. A function that receives two integers and return a string (i.e. a binary) would be written as `(integer(), integer() -> binary())`.\n\nWhen representing functions with multiple clauses, which may take different input types, we use intersections. For example, imagine the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nIf you give it an integer, it negates it. If you give it a boolean, it negates it.\n\nWe can say this function has the type `(integer() -> integer())` because it is capable of receiving an integer and returning an integer. In this case, `(integer() -> integer())` is a set that represents all functions that can receive an integer and return an integer. Even though this function can receive other arguments and return other values, it is still part of the `(integer() -> integer())` set.\n\nThis function also has the type `(boolean() -> boolean())`, because it also receives booleans and returns booleans. If you pass the function above to another function that expects `(boolean() -> boolean())`, type checking will succeed. Therefore, we can say the overall type of the function is `(integer() -> integer()) and (boolean() -> boolean())`. The intersection means the function belongs to both sets.\n\nAt this point, you may ask, why not a union? As a real-world example, take a t-shirt with green and yellow stripes. We can say the t-shirt belongs to the set of \"t-shirts with green color\". We can also say the t-shirt belongs to the set of \"t-shirts with yellow color\". Let's see the difference between unions and intersections:\n\n  * `(t_shirts_with_green() or t_shirts_with_yellow())` - contains t-shirts with either green or yellow, such as green, green and red, green and yellow, but also only yellow, yellow and red, etc.\n\n  * `(t_shirts_with_green() and t_shirts_with_yellow())` - contains t-shirts with both green and yellow (and maybe other colors)\n\nSince the t-shirt has both colors, we could say it belongs to the union of green and yellow t-shirts, but doing so would not capture the fact it is both green and yellow. Therefore it is more precise to say it belongs to the intersection of both sets. The same way that a function that goes from `(integer() -> integer())` and `(boolean() -> boolean())` is also an intersection. In practice, it is not useful to define the union of two functions in Elixir, so the compiler will point you to the right direction if you specify the wrong one.\n\n## The `dynamic()` type\n\nExisting Elixir programs do not have type declarations, but we still want to be able to type check them. This is done with the introduction of the `dynamic()` type.\n\nWhen Elixir sees the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nElixir type checks it as if the function had the type `(dynamic() -> dynamic())`. Then, based on patterns and guards, we can refine the value of the variable `x` to be `dynamic() and integer()` and `dynamic() and boolean()` for each clause respectively. We say `dynamic()` is a gradual type, which leads us to _gradual set-theoretic types_.\n\nThe simplest way to reason about `dynamic()` in Elixir is that it is a range of types. If you have a type `atom() or integer()`, the underlying code needs to work with both `atom() or integer()`. For example, if you call `Integer.to_string(var)`, and `var` has type `atom() or integer()`, the type system will emit a warning, because `Integer.to_string/1` does not accept atoms.\n\nHowever, by intersecting a type with `dynamic()`, we make the type gradual and therefore only a subset of the type needs to be valid. For instance, if you call `Integer.to_string(var)`, and `var` has type `dynamic() and (atom() or integer())`, the type system will not emit a warning, because `Integer.to_string/1` works with at least one of the types. For convenience, most programs will write `dynamic(atom() or integer())` instead of the intersection. They are equivalent.\n\nCompared to other gradually typed languages, the `dynamic()` type in Elixir is quite powerful: it restricts our program to certain types, via intersections, while still emitting warnings once it is certain the code will fail. This makes `dynamic()` an excellent tool for typing existing Elixir code with meaningful warnings.\n\nIf the user provides their own types, and those types are not `dynamic()`, then Elixir's type system behaves as a statically typed one. This brings us to one last property of dynamic types in Elixir: dynamic types are always at the root. For example, when you write a tuple of type `{:ok, dynamic()}`, Elixir will rewrite it to `dynamic({:ok, term()})`. While this has the downside that you cannot make part of a tuple/map/list gradual, only the whole tuple/map/list, it comes with the upside that dynamic is always explicitly at the root, making it harder to accidentally sneak `dynamic()` in a statically typed program.\n\n## Type inference\n\nType inference (or reconstruction) is the ability of a type system to automatically deduce, either partially or fully, the type of an expression at compile time. Type inference may occur at different levels. For example, many programming languages can automatically infer the types of variables, also known \"local type inference\", but not all can infer type signatures of functions.\n\nInferring type signatures comes with a series of trade-offs:\n\n  * Speed - type inference algorithms are often more computationally intensive than type checking algorithms.\n\n  * Expressiveness - in any given type system, the constructs that support inference are always a subset of those that can be type-checked. Therefore, if a programming language is restricted to fully reconstructed types, it is less expressive than a solely type checked counterpart.\n\n  * Incremental compilation - type inference complicates incremental compilation. If module A depends on module B, which depends on module C, a change to C may require the type signature in B to be reconstructed, which may then require A to be recomputed (and so on). This dependency chain may require large projects to explicitly add type signatures for stability and compilation efficiency.\n\n  * Cascading errors - when a user accidentally makes type errors or the code has conflicting assumptions, type inference may lead to less clear error messages as the type system tries to reconcile diverging type assumptions across code paths.\n\nOn the other hand, type inference offers the benefit of enabling type checking for functions and codebases without requiring the user to add type annotations. To balance these trade-offs, Elixir aims to provide type inference across dependencies: our goal is to infer the types of functions considering the current module, Elixir's standard library and your dependencies, while calls to modules within the same project are assumed to be `dynamic()`. Once types are inferred, then the whole project is type checked considering all modules and all types (inferred or otherwise).\n\nType inference in Elixir is best-effort: it doesn't guarantee it will find all possible type incompatibilities, only that it may find bugs where all combinations of a type _will_ fail, even in the absence of explicit type annotations. It is meant to be an efficient routine that brings developers some benefits of static typing, without requiring any effort from them and keeping the expressiveness of the language.\n\nIn the long term, Elixir developers who want static typing guarantees may explicitly add type signatures to their functions (see \"Roadmap\"). Any function with an explicit type signature will be typed checked against the user-provided annotations, as in other statically typed languages.\n\n### False positives\n\nElixir's type inference generally avoids emitting false positive type violations: which are warnings emitted by the type checker when there are no runtime errors. However, in some situations, those may happen and are documented below.\n\n#### `for`-comprehensions assume they may be executed zero, once, or multiple times\n\nFor comprehensions in Elixir assume they are executed at least once. Take this code:\n\n```elixir\ndef example(x, list) do\n  for _i <- list do\n    Atom.to_string(x)\n  end\n\n  x + 1\nend\n```\n\n`x + 1` will fail because it assumes `x` is an atom from the `Atom.to_string(x)` call, even though the function may raise no runtime error if `list` is an empty list. This is intentional, as it helps find discrepancies inside and outside comprehensions. You can address this by explicitly wrapping the comprehension in a `if list != [] do` block (or similar condition).\n\nSimilar, when using the `:reduce` option, Elixir assumes the list may be empty and therefore the accumulator must match the result type. Take this contrived example:\n\n```elixir\ndef example([_ | _] = list) do\n  Integer.to_string(\n    for i <- list, reduce: :unused do\n      _unused -> i * 2\n    end\n  )\nend\n```\n\nEven though the list is non-empty, for-comprehension always assumes the list can be empty, and the code above will fail because passing `:unused` to `Integer.to_string/1` is a typing violation (which will happen if list is empty). You fix this by making sure the accumulator matches the type of the comprehension body.\n\n#### Struct update syntax must be statically proven\n\nElixir will warn if you use the struct update syntax and it is not statically proven that the given value does not have said struct type. For example:\n\n```elixir\nuser = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\nEven though it is guaranteed at runtime that user is always a `User` struct. If the type system cannot prove it, it will emit a typing violation. This is how struct updates work by design. In such cases, you can address it by matching on the struct when the user variable is defined:\n\n```elixir\n%User{} = user = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\n## Roadmap\n\nAt this moment, Elixir implements type inference of all language constructs. The goal is to assess performance and collect feedback on the quality of error messages, before introducing user facing types.\n\nIf the results are satisfactory, the next milestone will include a mechanism for defining typed structs. Elixir programs frequently pattern match on structs, which reveals information about the struct fields, but it knows nothing about their respective types. By propagating types from structs and their fields throughout the program, we will increase the type system’s ability to find errors while further straining our type system implementation. Proposals including the required changes to the language surface will be sent to the community once we reach this stage.\n\nThe third milestone is to introduce set-theoretic type signatures for functions. Unfortunately, the existing Erlang Typespecs are not precise enough for set-theoretic types and they will be phased out of the language and have their postprocessing moved into a separate library once this stage concludes.\n\n## Resources\n\n  * (Paper) [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391)\n  * (Video) [\"The foundations of the Elixir type system\" by José Valim](https://youtu.be/giYbq4HmfGA)\n  * (Video) [\"Precision in type system design\" by José Valim](https://youtu.be/Ay-gnCqDw9o?t=102)\n\n## Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), and [Tidewave](https://tidewave.ai/).\n","lib/elixir/pages/references/compatibility-and-deprecations.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Compatibility and deprecations\n\nElixir is versioned according to a vMAJOR.MINOR.PATCH schema.\n\nElixir is currently at major version v1. A new backwards compatible minor release happens every 6 months. Patch releases are not scheduled and are made whenever there are bug fixes or security patches.\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.21           | Development\n1.20           | Bug fixes and security patches\n1.19           | Security patches only\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann) and on the [GitHub releases page](https://github.com/elixir-lang/elixir/releases).\n\nYou may also see [all releases](https://github.com/elixir-lang/elixir/releases) and [consult all disclosed vulnerabilities](https://github.com/elixir-lang/elixir/security) on GitHub.\n\nThere are currently no plans for a major v2 release.\n\n## Between non-major Elixir versions\n\nElixir minor and patch releases are backwards compatible: well-defined behaviors and documented APIs in a given version will continue working on future versions.\n\nAlthough we expect the vast majority of programs to remain compatible over time, it is impossible to guarantee that no future change will break any program. Under some unlikely circumstances, we may introduce changes that break existing code:\n\n  * Security: a security issue in the implementation may arise whose resolution requires backwards incompatible changes. We reserve the right to address such security issues.\n\n  * Bugs: if an API has undesired behavior, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.\n\n  * Compiler front-end: improvements may be done to the compiler, introducing new warnings for ambiguous modes and providing more detailed error messages. Those can lead to compilation errors (when running with `--warnings-as-errors`) or tooling failures when asserting on specific error messages (although one should avoid such). We reserve the right to do such improvements.\n\n  * Imports: new functions may be added to the `Kernel` module, which is auto-imported. They may collide with local functions defined in your modules. Collisions can be resolved in a backwards compatible fashion using `import Kernel, except: [...]` with a list of all functions you don't want to be imported from `Kernel`. We reserve the right to do such additions.\n\nIn order to continue evolving the language without introducing breaking changes, Elixir will rely on deprecations to demote certain practices and promote new ones. Our deprecation policy is outlined in the [\"Deprecations\" section](#deprecations).\n\nThe only exception to the compatibility guarantees above are experimental features, which will be explicitly marked as such, and do not provide any compatibility guarantee until they are stabilized.\n\n## Between Elixir and Erlang/OTP\n\nErlang/OTP versioning is independent from the versioning of Elixir. Erlang releases a new major version yearly. Our goal is to support the last three Erlang major versions by the time Elixir is released. The compatibility table is shown below.\n\nElixir version | Supported Erlang/OTP versions\n:------------- | :-------------------------------\n1.21           | 27 - 29\n1.20           | 27 - 29\n1.19           | 26 - 28\n1.18           | 25 - 27\n1.17           | 25 - 27\n1.16           | 24 - 26\n1.15           | 24 - 26\n1.14           | 23 - 25 (and Erlang/OTP 26 from v1.14.5)\n1.13           | 22 - 24 (and Erlang/OTP 25 from v1.13.4)\n1.12           | 22 - 24\n1.11           | 21 - 23 (and Erlang/OTP 24 from v1.11.4)\n1.10           | 21 - 22 (and Erlang/OTP 23 from v1.10.3)\n1.9            | 20 - 22\n1.8            | 20 - 22\n1.7            | 19 - 22\n1.6            | 19 - 20 (and Erlang/OTP 21 from v1.6.6)\n1.5            | 18 - 20\n1.4            | 18 - 19 (and Erlang/OTP 20 from v1.4.5)\n1.3            | 18 - 19\n1.2            | 18 - 18 (and Erlang/OTP 19 from v1.2.6)\n1.1            | 17 - 18\n1.0            | 17 - 17 (and Erlang/OTP 18 from v1.0.5)\n\nElixir may add compatibility to new Erlang/OTP versions on patch releases, such as support for Erlang/OTP 20 in v1.4.5. Those releases are made for convenience and typically contain the minimum changes for Elixir to run without errors, if any changes are necessary. Only the next minor release, in this case v1.5.0, effectively leverages the new features provided by the latest Erlang/OTP release.\n\n## Deprecations\n\n### Policy\n\nElixir deprecations happen in 3 steps:\n\n  1. The feature is soft-deprecated. It means both CHANGELOG and documentation must list the feature as deprecated but no warning is effectively emitted by running the code. There is no requirement to soft-deprecate a feature.\n\n  2. The feature is effectively deprecated by emitting warnings on usage. This is also known as hard-deprecation. In order to deprecate a feature, the proposed alternative MUST exist for AT LEAST THREE minor versions. For example, `Enum.uniq/2` was soft-deprecated in favor of `Enum.uniq_by/2` in Elixir v1.1. This means a deprecation warning may only be emitted by Elixir v1.4 or later.\n\n  3. The feature is removed. This can only happen on major releases. This means deprecated features in Elixir v1.x shall only be removed by Elixir v2.x.\n\n### Table of deprecations\n\nThe first column is the version the feature was hard deprecated. The second column shortly describes the deprecated feature and the third column explains the replacement and from which the version the replacement is available from.\n\nVersion | Deprecated feature                                  | Replaced by (available since)\n:-------| :-------------------------------------------------- | :---------------------------------------------------------------\n[v1.21] | `Macro.Env.fetch_alias/2` (and `fetch_macro_alias`) | `Macro.Env.expand_alias/4` (v1.17)\n[v1.20] | `<<x::size(y)>>` in patterns without `^`            | `<<x::size(^y)>>` (v1.15)\n[v1.20] | `File.stream!(path, modes, lines_or_bytes)`         | `File.stream!(path, lines_or_bytes, modes)` (v1.16)\n[v1.20] | `Kernel.ParallelCompiler.async/1`                   | `Kernel.ParallelCompiler.pmap/2` (v1.16)\n[v1.20] | `Logger.*_backend` functions                        | The `LoggerBackends` module from [`:logger_backends`](https://hex.pm/packages/logger_backends) package\n[v1.20] | `Logger.enable/1` and `Logger.disable/1`            | `Logger.put_process_level/2` and `Logger.delete_process_level/1` respectively (v1.15)\n[v1.19] | CLI configuration in `def project` inside `mix.exs` | Moving it to `def cli` (v1.14)\n[v1.19] | Using `,` to separate tasks in `mix do`             | Using `+` (v1.14)\n[v1.19] | `Logger`'s `:backends` configuration                | `Logger`'s `:default_handler` configuration (v1.15)\n[v1.19] | Passing a callback to `File.cp/3`, `File.cp!/3`, `File.cp_r/3`, and `File.cp_r!/3` | The `:on_conflict` option (v1.14)\n[v1.18] | `<%#` in EEx                                        | `<%!--` (v1.14) or `<% #` (v1.0)\n[v1.18] | `EEx.Engine.handle_text/2` callback in EEx          | `c:EEx.Engine.handle_text/3` (v1.14)\n[v1.18] | Returning a 2-arity function from `Enumerable.slice/1` | Returning a 3-arity function (v1.14)\n[v1.18] | Ranges with negative steps in `Range.new/2`         | Explicit steps in ranges (v1.11)\n[v1.18] | `Tuple.append/2`                                    | `Tuple.insert_at/3` (v1.0)\n[v1.18] | `mix cmd --app APP`                                 | `mix do --app APP` (v1.14)\n[v1.18] | `List.zip/1`                                        | `Enum.zip/1` (v1.0)\n[v1.18] | `Module.eval_quoted/3`                              | `Code.eval_quoted/3` (v1.0)\n[v1.17] | Single-quoted charlists (`'foo'`)                   | `~c\"foo\"` (v1.0)\n[v1.17] | `left..right` in patterns and guards                | `left..right//step` (v1.11)\n[v1.17] | `ExUnit.Case.register_test/4`                       | `register_test/6` (v1.10)\n[v1.17] | `:all` in `IO.read/2` and `IO.binread/2`            | `:eof` (v1.13)\n[v1.16] | `~R/.../`                                           | `~r/.../` (v1.0)\n[v1.16] | Ranges with negative steps in `Enum.slice/2`        | Explicit steps in ranges (v1.11)\n[v1.16] | Ranges with negative steps in `String.slice/2`      | Explicit steps in ranges (v1.11)\n[v1.15] | `Calendar.ISO.day_of_week/3`                        | `Calendar.ISO.day_of_week/4` (v1.11)\n[v1.15] | `Exception.exception?/1`                            | `Kernel.is_exception/1` (v1.11)\n[v1.15] | `Regex.regex?/1`                                    | `Kernel.is_struct/2` (`Kernel.is_struct(term, Regex)`) (v1.11)\n[v1.15] | `Logger.warn/2`                                     | `Logger.warning/2` (v1.11)\n[v1.14] | `use Bitwise`                                       | `import Bitwise` (v1.0)\n[v1.14] | `~~~/1`                                             | `bnot/1` (v1.0)\n[v1.14] | `Application.get_env/3` and similar in module body  | `Application.compile_env/3` (v1.10)\n[v1.14] | Compiled patterns in `String.starts_with?/2`        | Pass a list of strings instead (v1.0)\n[v1.14] | `Mix.Tasks.Xref.calls/1`                            | Compilation tracers (outlined in `Code`) (v1.10)\n[v1.14] | `$levelpad` in Logger                               | *None*\n[v1.14] | `<\\|>` as a custom operator                         | Another custom operator (v1.0)\n[v1.13] | `!` and `!=` in Version requirements                | `~>` or `>=` (v1.0)\n[v1.13] | `Mix.Config`                                        | `Config` (v1.9)\n[v1.13] | `:strip_beam` config to `mix escript.build`         | `:strip_beams` (v1.9)\n[v1.13] | `Macro.to_string/2`                                 | `Macro.to_string/1` (v1.0)\n[v1.13] | `System.get_pid/0`                                  | `System.pid/0` (v1.9)\n[v1.12] | `^^^/2`                                             | `bxor/2` (v1.0)\n[v1.12] | `@foo()` to read module attributes                  | Remove the parenthesis (v1.0)\n[v1.12] | `use EEx.Engine`                                    | Explicitly delegate to EEx.Engine instead (v1.0)\n[v1.12] | `:xref` compiler in Mix                             | Nothing (it always runs as part of the compiler now)\n[v1.11] | `Mix.Project.compile/2`                             | `Mix.Task.run(\"compile\", args)` (v1.0)\n[v1.11] | `Supervisor.Spec.worker/3` and `Supervisor.Spec.supervisor/3` | The new child specs outlined in `Supervisor` (v1.5)\n[v1.11] | `Supervisor.start_child/2` and `Supervisor.terminate_child/2` | `DynamicSupervisor` (v1.6)\n[v1.11] | `System.stacktrace/0`                               | `__STACKTRACE__` in `try/catch/rescue` (v1.7)\n[v1.10] | `Code.ensure_compiled?/1`                           | `Code.ensure_compiled/1` (v1.0)\n[v1.10] | `Code.load_file/2`                                  | `Code.require_file/2` (v1.0) or `Code.compile_file/2` (v1.7)\n[v1.10] | `Code.loaded_files/0`                               | `Code.required_files/0` (v1.7)\n[v1.10] | `Code.unload_file/1`                                | `Code.unrequire_files/1` (v1.7)\n[v1.10] | Passing non-chardata to `Logger.log/2`              | Explicitly convert to string with `to_string/1` (v1.0)\n[v1.10] | `:compile_time_purge_level` in `Logger` app environment | `:compile_time_purge_matching` in `Logger` app environment (v1.7)\n[v1.10] | `Supervisor.Spec.supervise/2`                       | The new child specs outlined in `Supervisor` (v1.5)\n[v1.10] | `:simple_one_for_one` strategy in `Supervisor`      | `DynamicSupervisor` (v1.6)\n[v1.10] | `:restart` and `:shutdown` in `Task.Supervisor.start_link/1` | `:restart` and `:shutdown` in `Task.Supervisor.start_child/3` (v1.6)\n[v1.9]  | Enumerable keys in `Map.drop/2`, `Map.split/2`, and `Map.take/2` | Call `Enum.to_list/1` on the second argument before hand (v1.0)\n[v1.9]  | `Mix.Project.load_paths/1`                          | `Mix.Project.compile_path/1` (v1.0)\n[v1.9]  | Passing `:insert_replaced` to `String.replace/4`    | Use `:binary.replace/4` (v1.0)\n[v1.8]  | Passing a non-empty list to `Collectable.into/1`    | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `:into` in `for/1`      | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `Enum.into/2`           | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Time units in its plural form, such as: `:seconds`, `:milliseconds`, and the like | Use the singular form, such as: `:second`, `:millisecond`, and so on (v1.4)\n[v1.8]  | `Inspect.Algebra.surround/3`                        | `Inspect.Algebra.concat/2` and `Inspect.Algebra.nest/2` (v1.0)\n[v1.8]  | `Inspect.Algebra.surround_many/6`                   | `Inspect.Algebra.container_doc/6` (v1.6)\n[v1.9]  | `--detached` in `Kernel.CLI`                        | `--erl \"-detached\"` (v1.0)\n[v1.8]  | `Kernel.ParallelCompiler.files/2`                   | `Kernel.ParallelCompiler.compile/2` (v1.6)\n[v1.8]  | `Kernel.ParallelCompiler.files_to_path/2`           | `Kernel.ParallelCompiler.compile_to_path/2` (v1.6)\n[v1.8]  | `Kernel.ParallelRequire.files/2`                    | `Kernel.ParallelCompiler.require/2` (v1.6)\n[v1.8]  | Returning `{:ok, contents}` or `:error` from `Mix.Compilers.Erlang.compile/6`'s callback | Return `{:ok, contents, warnings}` or `{:error, errors, warnings}` (v1.6)\n[v1.8]  | `System.cwd/0` and `System.cwd!/0`                  | `File.cwd/0` and `File.cwd!/0` respectively (v1.0)\n[v1.7]  | `Code.get_docs/2`                                   | `Code.fetch_docs/1` (v1.7)\n[v1.7]  | `Enum.chunk/2,3,4`                                  | `Enum.chunk_every/2` and [`Enum.chunk_every/3,4`](`Enum.chunk_every/4`) (v1.5)\n[v1.7]  | Calling `super/1` in`GenServer` callbacks           | Implementing the behaviour explicitly without calling `super/1` (v1.0)\n[v1.7]  | [`not left in right`](`in/2`)                | [`left not in right`](`in/2`) (v1.5)\n[v1.7]  | `Registry.start_link/3`                             | `Registry.start_link/1` (v1.5)\n[v1.7]  | `Stream.chunk/2,3,4`                                | `Stream.chunk_every/2` and [`Stream.chunk_every/3,4`](`Stream.chunk_every/4`) (v1.5)\n[v1.6]  | `Enum.partition/2`                                  | `Enum.split_with/2` (v1.4)\n[v1.6]  | `Macro.unescape_tokens/1,2`                         | Use `Enum.map/2` to traverse over the arguments (v1.0)\n[v1.6]  | `Module.add_doc/6`                                  | [`@doc`](`Module`) module attribute (v1.0)\n[v1.6]  | `Range.range?/1`                                    | Pattern match on [`_.._`](`../2`) (v1.0)\n[v1.5]  | `()` to mean `nil`                                  | `nil` (v1.0)\n[v1.5]  | `char_list/0` type                                  | `t:charlist/0` type (v1.3)\n[v1.5]  | `Atom.to_char_list/1`                               | `Atom.to_charlist/1` (v1.3)\n[v1.5]  | `Enum.filter_map/3`                                 | `Enum.filter/2` + `Enum.map/2` or `for/1` comprehensions (v1.0)\n[v1.5]  | `Float.to_char_list/1`                              | `Float.to_charlist/1` (v1.3)\n[v1.5]  | `GenEvent` module                                   | `Supervisor` and `GenServer` (v1.0)\n[v1.5]  | `<%=` in middle and end expressions in `EEx`        | Use `<%` (`<%=` is allowed only in start expressions) (v1.0)\n[v1.5]  | `:as_char_lists` value in `t:Inspect.Opts.t/0` type | `:as_charlists` value (v1.3)\n[v1.5]  | `:char_lists` key in `t:Inspect.Opts.t/0` type      | `:charlists` key (v1.3)\n[v1.5]  | `Integer.to_char_list/1,2`                          | `Integer.to_charlist/1` and `Integer.to_charlist/2` (v1.3)\n[v1.5]  | `to_char_list/1`                                    | `to_charlist/1` (v1.3)\n[v1.5]  | `List.Chars.to_char_list/1`                         | `List.Chars.to_charlist/1` (v1.3)\n[v1.5]  | `@compile {:parse_transform, _}` in `Module`        | *None*\n[v1.5]  | `Stream.filter_map/3`                               | `Stream.filter/2` + `Stream.map/2` (v1.0)\n[v1.5]  | `String.ljust/3` and `String.rjust/3`               | Use `String.pad_leading/3` and `String.pad_trailing/3` with a binary padding (v1.3)\n[v1.5]  | `String.lstrip/1` and `String.rstrip/1`             | `String.trim_leading/1` and `String.trim_trailing/1` (v1.3)\n[v1.5]  | `String.lstrip/2` and `String.rstrip/2`             | Use `String.trim_leading/2` and `String.trim_trailing/2` with a binary as second argument (v1.3)\n[v1.5]  | `String.strip/1` and `String.strip/2`               | `String.trim/1` and `String.trim/2` (v1.3)\n[v1.5]  | `String.to_char_list/1`                             | `String.to_charlist/1` (v1.3)\n[v1.4]  | Anonymous functions with no expression after `->`   | Use an expression or explicitly return `nil` (v1.0)\n[v1.4]  | Support for making [private functions](`defp/2`) overridable | Use [public functions](`def/2`) (v1.0)\n[v1.4]  | Variable used as function call                      | Use parentheses (v1.0)\n[v1.4]  | `Access.key/1`                                      | `Access.key/2` (v1.3)\n[v1.4]  | `Behaviour` module                                  | `@callback` module attribute (v1.0)\n[v1.4]  | `Enum.uniq/2`                                       | `Enum.uniq_by/2` (v1.2)\n[v1.4]  | `Float.to_char_list/2`                              | `:erlang.float_to_list/2` (Erlang/OTP 17)\n[v1.4]  | `Float.to_string/2`                                 | `:erlang.float_to_binary/2` (Erlang/OTP 17)\n[v1.4]  | `HashDict` module                                   | `Map` (v1.2)\n[v1.4]  | `HashSet` module                                    | `MapSet` (v1.1)\n[v1.4]  | `IEx.Helpers.import_file/2`                         | `IEx.Helpers.import_file_if_available/1` (v1.3)\n[v1.4]  | `Mix.Utils.camelize/1`                              | `Macro.camelize/1` (v1.2)\n[v1.4]  | `Mix.Utils.underscore/1`                            | `Macro.underscore/1` (v1.2)\n[v1.4]  |  Multi-letter aliases in `OptionParser`             | Use single-letter aliases (v1.0)\n[v1.4]  | `Set` module                                        | `MapSet` (v1.1)\n[v1.4]  | `Stream.uniq/2`                                     | `Stream.uniq_by/2` (v1.2)\n[v1.3]  | `\\x{X*}` inside strings/sigils/charlists            | `\\uXXXX` or `\\u{X*}` (v1.1)\n[v1.3]  | `Dict` module                                       | `Keyword` (v1.0) or `Map` (v1.2)\n[v1.3]  | `:append_first` option in `defdelegate/2`           | Define the function explicitly (v1.0)\n[v1.3]  | Map/dictionary as 2nd argument in `Enum.group_by/3` | `Enum.reduce/3` (v1.0)\n[v1.3]  | `Keyword.size/1`                                    | `length/1` (v1.0)\n[v1.3]  | `Map.size/1`                                        | `map_size/1` (v1.0)\n[v1.3]  | `/r` option in `Regex`                              | `/U` (v1.1)\n[v1.3]  | `Set` behaviour                                     | `MapSet` data structure (v1.1)\n[v1.3]  | `String.valid_character?/1`                         | `String.valid?/1` (v1.0)\n[v1.3]  | `Task.find/2`                                       | Use direct message matching (v1.0)\n[v1.3]  | Non-map as 2nd argument in `URI.decode_query/2`     | Use a map (v1.0)\n[v1.2]  | `Dict` behaviour                                    | `Map` and `Keyword` (v1.0)\n[v1.1]  | `?\\xHEX`                                            | `0xHEX` (v1.0)\n[v1.1]  | `Access` protocol                                   | `Access` behaviour (v1.1)\n[v1.1]  | `as: true \\| false` in `alias/2` and `require/2`    | *None*\n\n[v1.1]: https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md#4-deprecations\n[v1.2]: https://github.com/elixir-lang/elixir/blob/v1.2/CHANGELOG.md#changelog-for-elixir-v12\n[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations\n[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations\n[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations\n[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations\n[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations\n[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations\n[v1.9]: https://github.com/elixir-lang/elixir/blob/v1.9/CHANGELOG.md#4-hard-deprecations\n[v1.10]: https://github.com/elixir-lang/elixir/blob/v1.10/CHANGELOG.md#4-hard-deprecations\n[v1.11]: https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#4-hard-deprecations\n[v1.12]: https://github.com/elixir-lang/elixir/blob/v1.12/CHANGELOG.md#4-hard-deprecations\n[v1.13]: https://github.com/elixir-lang/elixir/blob/v1.13/CHANGELOG.md#4-hard-deprecations\n[v1.14]: https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#4-hard-deprecations\n[v1.15]: https://github.com/elixir-lang/elixir/blob/v1.15/CHANGELOG.md#4-hard-deprecations\n[v1.16]: https://github.com/elixir-lang/elixir/blob/v1.16/CHANGELOG.md#4-hard-deprecations\n[v1.17]: https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md#4-hard-deprecations\n[v1.18]: https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md#4-hard-deprecations\n[v1.19]: https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md#4-hard-deprecations\n[v1.20]: https://github.com/elixir-lang/elixir/blob/v1.20/CHANGELOG.md#4-hard-deprecations\n[v1.21]: https://github.com/elixir-lang/elixir/blob/main/CHANGELOG.md#4-hard-deprecations\n","lib/elixir/pages/references/unicode-syntax.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Unicode syntax\n\nElixir supports Unicode throughout the language. This document is a complete reference of how\nElixir supports Unicode in its syntax.\n\nStrings (`\"olá\"`) and charlists (`'olá'`) support Unicode since Elixir v1.0. Strings are UTF-8 encoded. Charlists are lists of Unicode code points. In such cases, the contents are kept as written by developers, without any transformation.\n\nElixir also supports Unicode in variables, atoms, and calls since Elixir v1.5. The focus of this document is to provide a high-level introduction to how Elixir allows Unicode in its syntax. We also provide technical documentation describing how Elixir complies with the Unicode specification.\n\nTo check the Unicode version of your current Elixir installation, run `String.Unicode.version()`.\n\n## Introduction\n\nElixir allows Unicode characters in its variables, atoms, and calls. However, the Unicode characters must still obey the rules of the language syntax. In particular, variables and calls cannot start with an uppercase letter. From now on, we will refer to those terms as identifiers.\n\nThe characters allowed in identifiers are the ones specified by Unicode. Generally speaking, it is restricted to characters typically used by the writing system of human languages still in activity. In particular, it excludes symbols such as emojis, alternate numeric representations, musical notes, and the like.\n\nElixir imposes many restrictions on identifiers for security purposes. For example, the word \"josé\" can be written in two ways in Unicode: as the combination of the characters `j o s é` and as a combination of the characters `j o s e ́ `, where the accent is its own character. The former is called NFC form and the latter is the NFD form. Elixir normalizes all characters to be the in the NFC form.\n\nElixir also disallows mixed-scripts which are not explicitly separated by `_`. For example, it is not possible to name a variable `аdmin`, where `а` is in Cyrillic and the remaining characters are in Latin. Doing so will raise the following error:\n\n```text\n** (SyntaxError) invalid mixed-script identifier found: аdmin\n\nMixed-script identifiers are not supported for security reasons. 'аdmin' is made of the following scripts:\n\n  \\u0430 а {Cyrillic}\n  \\u0064 d {Latin}\n  \\u006D m {Latin}\n  \\u0069 i {Latin}\n  \\u006E n {Latin}\n\nMake sure all characters in the identifier resolve to a single script or a highly\nrestrictive script. See https://elixir.hexdocs.pm/unicode-syntax.html for more information.\n```\n\nFinally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.\n\nThat's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.\n\nFor the technical details, see the next sections that cover the technical Unicode requirements.\n\n## Unicode Standard Annex #31\n\nElixir conforms to the standards outlined in the [Unicode Standard Annex #31: Unicode Identifiers and Syntax](https://unicode.org/reports/tr31/), version 17.0.\n\n### R1. Default Identifiers\n\nThe general Elixir identifier rule is specified as:\n\n    <Identifier> := <Start> <Continue>* <Ending>?\n\nwhere `<Start>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> characters derived from the Unicode General Category of uppercase letters, lowercase letters, titlecase letters, modifier letters, other letters, letter numbers, plus `Other_ID_Start`, minus `Pattern_Syntax` and `Pattern_White_Space` code points\n>\n> In set notation: `[\\p{L}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\nand `<Continue>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> ID_Start characters, plus characters having the Unicode General Category of nonspacing marks, spacing combining marks, decimal number, connector punctuation, plus `Other_ID_Continue`, minus `Pattern_Syntax` and `Pattern_White_Space` code points.\n>\n> In set notation: `[\\p{ID_Start}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}\\p{Other_ID_Continue}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n`<Ending>` is an addition specific to Elixir that includes only the code points `?` (003F) and `!` (0021).\n\nThe spec also provides a `<Medial>` set, but Elixir does not include any character on this set. Therefore, the identifier rule has been simplified to consider this.\n\nElixir does not allow the use of ZWJ or ZWNJ in identifiers and therefore does not implement R1a. Bidirectional control characters are also not supported. R1b is guaranteed for backwards compatibility purposes.\n\n#### Atoms\n\nUnicode atoms in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Continue>` additionally includes the code point `@` (0040)\n\nNote atoms can also be quoted, which allows any characters, such as `:\"hello elixir\"`. All Elixir operators are also valid atoms, such as `:+`, `:@`, `:|>`, and others. The full description of valid atoms is available in the [\"Atoms\" section in the syntax reference](syntax-reference.md#atoms).\n\n#### Variables, local calls, and remote calls\n\nVariables in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Start>` additionally excludes Lu (letter uppercase) and Lt (letter titlecase) characters\n\nIn set notation: `[\\u{005F}\\p{Ll}\\p{Lm}\\p{Lo}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n#### Aliases\n\nAliases in Elixir only allow ASCII characters, starting in uppercase, and no punctuation characters.\n\n### R3. Pattern_White_Space and Pattern_Syntax Characters\n\nElixir supports only code points `\\t` (0009), `\\n` (000A), `\\r` (000D) and `\\s` (0020) as whitespace and therefore does not follow requirement R3. R3 requires a wider variety of whitespace and syntax characters to be supported.\n\n### R4. Equivalent Normalized Identifiers\n\nIdentifiers in Elixir are case sensitive.\n\nElixir normalizes all atoms and variables to NFC form. Quoted-atoms and strings can, however, be in any form and are not verified by the parser.\n\nIn other words, the atom `:josé` can only be written with the code points `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301`, but Elixir will rewrite it to the former (from Elixir 1.14). On the other hand, `:\"josé\"` may be written as `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301` and its form will be retained, since it is written between quotes.\n\nChoosing requirement R4 automatically excludes requirements R5, R6, and R7.\n\n## Unicode Technical Standard #39\n\nElixir conforms to the clauses outlined in the [Unicode Technical Standard #39](https://unicode.org/reports/tr39/) on Security, version 17.0.\n\n### C1. General Security Profile for Identifiers\n\nElixir will not allow tokenization of identifiers with codepoints in `\\p{Identifier_Status=Restricted}`, except for the outlined 'Additional normalizations' section below.\n\n> An implementation following the General Security Profile does not permit any characters in \\p{Identifier_Status=Restricted}, ...\n\nFor instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, is an uncommon codepoint and will trigger a warning.\n\n### C2. Confusable detection\n\nElixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.\n\nWe use the means described in Section 4, 'Confusable Detection', with one noted modification:\n\n> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.\n\nElixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).\n\n### C3. Mixed Script Detection\n\nElixir will not allow tokenization of mixed-script identifiers unless it is via chunks separated by an underscore, like `http_сервер`. We use the means described in Section 5.1, Mixed-Script Detection, to determine if script mixing is occurring, with the 'Additional Normalizations' documented in.\n\nExamples: Elixir allows an identifiers like `幻한`, even though it includes characters from multiple 'scripts', as Han characters may be mixed with Japanese and Korean, according to the rules from UTS 39 5.1. When mixing Latin and Japanese scripts, underscores are necessary, as in `:T_シャツ` (the Japanese word for 't-shirt' with an additional underscore separating the letter T).\n\nElixir does not allow code like `if аdmin, do: :ok, else: :err`, where the scriptset for the 'a' character is {Cyrillic} but all other characters have scriptsets of {Latin}. The scriptsets fail to resolve and a descriptive error is shown.\n\n### C4, C5 (inapplicable)\n\n'C4 - Restriction Level detection' conformance is not claimed and does not apply to identifiers in code; rather, it applies to classifying the level of safety of a given arbitrary string into one of 5 restriction levels.\n\n'C5 - Mixed number detection' conformance is inapplicable as Elixir does not support Unicode numbers.\n\n### Addition Normalizations\n\nAs of Elixir 1.14, some codepoints in `\\p{Identifier_Status=Restricted}` are *normalized* to other, unrestricted codepoints.\n\nThis is currently only applied to translate MICRO SIGN (`µ`) to Greek lowercase mu (`μ`).\n\nThe normalization avoids confusability and the mixed-script detection is modified to the extent that the normalized codepoint is given the union of scriptsets from both characters.\n\n  * For instance, in the example of MICRO => MU, MICRO was a 'Common'-script character - the same script given to the '_' underscore codepoint - and thus the normalized character's scriptset will be {Greek, Common}. 'Common' intersects with all non-empty scriptsets, and thus the normalized character can be used in tokens written in any script without causing script mixing.\n\n  * The code points normalized in this fashion are those that are in use in the community, and judged not likely to cause issues with unsafe script mixing. For instance, the MICRO or MU codepoint may be used in an atom or variable dealing with microseconds.\n","lib/elixir/pages/references/syntax-reference.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Syntax reference\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). This means the Elixir syntax is mostly uniform with a handful of \"syntax sugar\" constructs to reduce the noise in common Elixir idioms.\n\nThis document covers all of Elixir syntax constructs as a reference and then discuss their exact AST representation.\n\n## Reserved words\n\nThese are the reserved words in the Elixir language. They are detailed throughout this guide but summed up here for convenience:\n\n  * `true`, `false`, `nil` - used as atoms\n  * `when`, `and`, `or`, `not`, `in` - used as operators\n  * `fn` - used for anonymous function definitions\n  * `do`, `end`, `catch`, `rescue`, `after`, `else` - used in do-end blocks\n\n## Data types\n\n### Numbers\n\nIntegers (`1234`) and floats (`123.4`) in Elixir are represented as a sequence of digits that may be separated by underscore for readability purposes, such as `1_000_000`. Integers never contain a dot (`.`) in their representation. Floats contain a dot and at least one other digit after the dot. Floats also support the scientific notation, such as `123.4e10` or `123.4E10`.\n\n### Atoms\n\nUnquoted atoms start with a colon (`:`) which must be immediately followed by a Unicode letter or an underscore. The atom may continue using a sequence of Unicode letters, numbers, underscores, and `@`. Atoms may end in `!` or `?`. Valid unquoted atoms are: `:ok`, `:ISO8601`, and `:integer?`.\n\nIf the colon is immediately followed by a pair of double- or single-quotes surrounding the atom name, the atom is considered quoted. In contrast with an unquoted atom, this one can be made of any Unicode character (not only letters), such as `:'🌢 Elixir'`, `:\"++olá++\"`, and `:\"123\"`.\n\nQuoted and unquoted atoms with the same name are considered equivalent, so `:atom`, `:\"atom\"`, and `:'atom'` represent the same atom. The only catch is that the compiler will warn when quotes are used in atoms that do not need to be quoted.\n\nAll operators in Elixir are also valid atoms. Valid examples are `:foo`, `:FOO`, `:foo_42`, `:foo@bar`, and `:++`. Invalid examples are `:@foo` (`@` is not allowed at start), `:123` (numbers are not allowed at start), and `:(*)` (not a valid operator).\n\n`true`, `false`, and `nil` are reserved words that are represented by the atoms `:true`, `:false` and `:nil` respectively.\n\nTo learn more about all Unicode characters allowed in atom, see the [Unicode syntax](unicode-syntax.md) document.\n\n### Strings\n\nSingle-line strings in Elixir are written between double-quotes, such as `\"foo\"`. Any double-quote inside the string must be escaped with `\\ `. Strings support Unicode characters and are stored as UTF-8 encoded binaries.\n\nMulti-line strings in Elixir are called heredocs. They are written with three double-quotes, and can have unescaped quotes within them. The resulting string will end with a newline. The indentation of the last `\"\"\"` is used to strip indentation from the inner string. For example:\n\n```elixir\niex> test = \"\"\"\n...>     this\n...>     is\n...>     a\n...>     test\n...> \"\"\"\n\"    this\\n    is\\n    a\\n    test\\n\"\niex> test = \"\"\"\n...>     This\n...>     Is\n...>     A\n...>     Test\n...>     \"\"\"\n\"This\\nIs\\nA\\nTest\\n\"\n```\n\nStrings are always represented as themselves in the AST.\n\n### Charlists\n\nCharlists are lists of non-negative integers where each integer represents a Unicode code point.\n\n```elixir\niex(6)> 'abc' === [97, 98, 99]\ntrue\n```\n\nCharlists are written in single-quotes, such as `'foo'`. Any single-quote inside the string must be escaped with `\\ `.\nMulti-line charlists are written with three single-quotes (`'''`), the same way multi-line strings are.\nHowever, this syntax is deprecated in favor of the charlist sigil `~c`.\n\nCharlists are always represented as themselves in the AST.\n\nFor more in-depth information, please read the \"Charlists\" section in the `List` module.\n\n### Lists, tuples and binaries\n\nData structures such as lists, tuples, and binaries are marked respectively by the delimiters `[...]`, `{...}`, and `<<...>>`. Each element is separated by comma. A trailing comma is also allowed, such as in `[1, 2, 3,]`.\n\n### Maps and keyword lists\n\nMaps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{\"hello\" => 1, 2 => \"world\"}`.\n\nBoth keyword lists (list of two-element tuples where the first element is an atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: \"world\"}` is equivalent to `%{:hello => \"world\"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.\n\n### Structs\n\nStructs built on the map syntax by passing the struct name between `%` and `{`. For example, `%User{...}`.\n\n## Expressions\n\n### Variables\n\nVariables in Elixir must start with an underscore or a Unicode letter that is not in uppercase or titlecase. The variable may continue using a sequence of Unicode letters, numbers, and underscores. Variables may end in `?` or `!`. To learn more about all Unicode characters allowed in variables, see the [Unicode syntax](unicode-syntax.md) document.\n\n[Elixir's naming conventions](naming-conventions.md) recommend variables to be in `snake_case` format.\n\n### Non-qualified calls (local calls)\n\nNon-qualified calls, such as `add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments.\n\nParentheses are required for zero-arity calls (i.e. calls without arguments), to avoid ambiguity with variables. If parentheses are used, they must immediately follow the function name *without spaces*. For example, `add (1, 2)` is a syntax error, since `(1, 2)` is treated as an invalid block which is attempted to be given as a single argument to `add`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Operators\n\nAs many programming languages, Elixir also support operators as non-qualified calls with their precedence and associativity rules. Constructs such as `=`, `when`, `&` and `@` are simply treated as operators. See [the Operators page](operators.md) for a full reference.\n\n### Qualified calls (remote calls)\n\nQualified calls, such as `Math.add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments. Qualified calls also support operators, such as `Kernel.+(1, 2)`. Elixir also allows the function name to be written between double- or single-quotes, allowing any character in between the quotes, such as `Math.\"++add++\"(1, 2)`.\n\nSimilar to non-qualified calls, parentheses have different meaning for zero-arity calls (i.e. calls without arguments). If parentheses are used, such as `mod.fun()`, it means a function call. If parenthesis are skipped, such as `map.field`, it means accessing a field of a map.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Aliases\n\nAliases are constructs that expand to atoms at compile-time. The alias `String` expands to the atom `:\"Elixir.String\"`. Aliases must start with an ASCII uppercase character which may be followed by any ASCII letter, number, or underscore. Non-ASCII characters are not supported in aliases.\n\nMultiple aliases can be joined with `.`, such as `MyApp.String`, and it expands to the atom `:\"Elixir.MyApp.String\"`. The dot is effectively part of the name but it can also be used for composition. If you define `alias MyApp.Example, as: Example` in your code, then `Example` will always expand to `:\"Elixir.MyApp.Example\"` and `Example.String` will expand to `:\"Elixir.MyApp.Example.String\"`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend aliases to be in `CamelCase` format.\n\n### Module attributes\n\nModule attributes are module-specific storage and are written as the composition of the unary operator `@` with variables and local calls. For example, to write to a module attribute named `foo`, use `@foo \"value\"`, and use `@foo` to read from it. Given module attributes are written using existing constructs, they follow the same rules above defined for operators, variables, and local calls.\n\n### Blocks\n\nBlocks are multiple Elixir expressions separated by newlines or semi-colons. A new block may be created at any moment by using parentheses.\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is used to establish a relationship between left and right, commonly referred as clauses. The left side may have zero, one, or more arguments; the right side is zero, one, or more expressions separated by new line. The `->` may appear one or more times between one of the following terminators: `do`-`end`, `fn`-`end` or `(`-`)`. When `->` is used, only other clauses are allowed between those terminators. Mixing clauses and regular expressions is invalid syntax.\n\nIt is seen on `case` and `cond` constructs between `do` and `end`:\n\n```elixir\ncase 1 do\n  2 -> 3\n  4 -> 5\nend\n\ncond do\n  true -> false\nend\n```\n\nSeen in typespecs between `(` and `)`:\n\n```elixir\n(integer(), boolean() -> integer())\n```\n\nIt is also used between `fn` and `end` for building anonymous functions:\n\n```elixir\nfn\n  x, y -> x + y\nend\n```\n\n### Sigils\n\nSigils start with `~` and are followed by one lowercase letter or by one or more uppercase letters, immediately followed by one of the following pairs:\n\n  * `(` and `)`\n  * `{` and `}`\n  * `[` and `]`\n  * `<` and `>`\n  * `\"` and `\"`\n  * `'` and `'`\n  * `|` and `|`\n  * `/` and `/`\n\nAfter closing the pair, zero or more ASCII letters and digits can be given as a modifier. Sigils are expressed as non-qualified calls prefixed with `sigil_` where the first argument is the sigil contents as a string and the second argument is a list of integers as modifiers:\n\nIf the sigil letter is in uppercase, no interpolation is allowed in the sigil, otherwise its contents may be dynamic. Compare the results of the sigils below for more information:\n\n```elixir\n~s/f#{\"o\"}o/\n~S/f#{\"o\"}o/\n```\n\nSigils are useful to encode text with their own escaping rules, such as regular expressions, datetimes, and others.\n\n## The Elixir AST\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). Elixir's AST is a regular Elixir data structure composed of the following elements:\n\n  * atoms - such as `:foo`\n  * integers - such as `42`\n  * floats - such as `13.1`\n  * strings - such as `\"hello\"`\n  * lists - such as `[1, 2, 3]`\n  * tuples with two elements - such as `{\"hello\", :world}`\n  * tuples with three elements, representing calls or variables, as explained next\n\nThe building block of Elixir's AST is a call, such as:\n\n```elixir\nsum(1, 2, 3)\n```\n\nwhich is represented as a tuple with three elements:\n\n```elixir\n{:sum, meta, [1, 2, 3]}\n```\n\nthe first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.\n\nWe can retrieve the AST for any Elixir expression by calling `quote`:\n\n```elixir\nquote do\n  sum()\nend\n#=> {:sum, [], []}\n```\n\nVariables are also represented using a tuple with three elements and a combination of lists and atoms, for example:\n\n```elixir\nquote do\n  sum\nend\n#=> {:sum, [], Elixir}\n```\n\nYou can see that variables are also represented with a tuple, except the third element is an atom expressing the variable context.\n\nOver the course of this section, we will explore many Elixir syntax constructs alongside their AST representations.\n\n### Operators\n\nOperators are treated as non-qualified calls:\n\n```elixir\nquote do\n  1 + 2\nend\n#=> {:+, [], [1, 2]}\n```\n\nNote that `.` is also an operator. Remote calls use the dot in the AST with two arguments, where the second argument is always an atom:\n\n```elixir\nquote do\n  foo.bar(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}\n```\n\nCalling anonymous functions uses the dot in the AST with a single argument, mirroring the fact the function name is \"missing\" from right side of the dot:\n\n```elixir\nquote do\n  foo.(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}\n```\n\n### Aliases\n\nAliases are represented by an `__aliases__` call with each segment separated by a dot as an argument:\n\n```elixir\nquote do\n  Foo.Bar.Baz\nend\n#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}\n\nquote do\n  __MODULE__.Bar.Baz\nend\n#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}\n```\n\nAll arguments, except the first, are guaranteed to be atoms.\n\n### Data structures\n\nRemember that lists are literals, so they are represented as themselves in the AST:\n\n```elixir\nquote do\n  [1, 2, 3]\nend\n#=> [1, 2, 3]\n```\n\nTuples have their own representation, except for two-element tuples, which are represented as themselves:\n\n```elixir\nquote do\n  {1, 2}\nend\n#=> {1, 2}\n\nquote do\n  {1, 2, 3}\nend\n#=> {:{}, [], [1, 2, 3]}\n```\n\nBinaries have a representation similar to tuples, except they are tagged with `:<<>>` instead of `:{}`:\n\n```elixir\nquote do\n  <<1, 2, 3>>\nend\n#=> {:<<>>, [], [1, 2, 3]}\n```\n\nThe same applies to maps, where pairs are treated as a list of tuples with two elements:\n\n```elixir\nquote do\n  %{1 => 2, 3 => 4}\nend\n#=> {:%{}, [], [{1, 2}, {3, 4}]}\n```\n\n### Blocks\n\nBlocks are represented as a `__block__` call with each line as a separate argument:\n\n```elixir\nquote do\n  1\n  2\n  3\nend\n#=> {:__block__, [], [1, 2, 3]}\n\nquote do 1; 2; 3; end\n#=> {:__block__, [], [1, 2, 3]}\n```\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is represented similar to operators except that they are always part of a list, its left side represents a list of arguments and the right side is an expression.\n\nFor example, in `case` and `cond`:\n\n```elixir\nquote do\n  case 1 do\n    2 -> 3\n    4 -> 5\n  end\nend\n#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}\n\nquote do\n  cond do\n    true -> false\n  end\nend\n#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}\n```\n\nBetween `(` and `)`:\n\n```elixir\nquote do\n  (1, 2 -> 3\n   4, 5 -> 6)\nend\n#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]\n```\n\nBetween `fn` and `end`:\n\n```elixir\nquote do\n  fn\n    1, 2 -> 3\n    4, 5 -> 6\n  end\nend\n#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}\n```\n\n### Qualified tuples\n\nQualified tuples (`foo.{bar, baz}`) are represented by a `{:., [], [expr, :{}]}` call, where the `expr` represents the left hand side of the dot, and the arguments represent the elements inside the curly braces. This is used in Elixir to provide multi aliases:\n\n```elixir\nquote do\n  Foo.{Bar, Baz}\nend\n#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}\n```\n\n### `do`-`end` blocks\n\nElixir's `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:\n\n```elixir\nif true do\n  this\nelse\n  that\nend\n```\n\nis the same as:\n\n```elixir\nif(true, do: (this), else: (that))\n```\n\nWhile the construct above does not require custom nodes in Elixir's AST, they are restricted only to certain keywords, listed next:\n\n  * `after`\n  * `catch`\n  * `else`\n  * `rescue`\n\nYou will find them in constructs such as `receive`, `try`, and others. You can also find more examples in [the Optional Syntax chapter](../getting-started/optional-syntax.md).\n","lib/elixir/pages/references/typespecs.md":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Typespecs reference\n\n> #### Typespecs are not set-theoretic types {: .warning}\n>\n> Elixir is in the process of implementing its\n> [own type system](./gradual-set-theoretic-types.md) based on set-theoretic types.\n> Typespecs, which are described in the following document, are a distinct notation\n> for declaring types and specifications based on Erlang.\n> Typespecs may be phased out as the set-theoretic type effort moves forward.\n\nElixir is a dynamically typed language, and as such, type specifications are never used by the compiler to optimize or modify code. Still, using type specifications is useful because:\n\n  * they provide documentation (for example, tools such as [`ExDoc`](https://ex-doc.hexdocs.pm/) show type specifications in the documentation)\n  * they're used by tools such as [Dialyzer](`:dialyzer`), that can analyze code with typespecs to find type inconsistencies and possible bugs\n\nType specifications (most often referred to as *typespecs*) are defined in different contexts using the following attributes:\n\n  * `@type`\n  * `@opaque`\n  * `@typep`\n  * `@spec`\n  * `@callback`\n  * `@macrocallback`\n\nIn addition, you can use `@typedoc` to document a custom `@type` definition.\n\nSee the \"User-defined types\" and \"Defining a specification\" sub-sections below for more information on defining types and typespecs.\n\n## A simple example\n\n    defmodule StringHelpers do\n      @typedoc \"A word from the dictionary\"\n      @type word() :: String.t()\n\n      @spec long_word?(word()) :: boolean()\n      def long_word?(word) when is_binary(word) do\n        String.length(word) > 8\n      end\n    end\n\nIn the example above:\n\n  * We declare a new type (`word()`) that is equivalent to the string type (`String.t()`).\n\n  * We describe the type using a `@typedoc`, which will be included in the generated documentation.\n\n  * We specify that the `long_word?/1` function takes an argument of type `word()` and\n    returns a boolean (`boolean()`), that is, either `true` or `false`.\n\n## Types and their syntax\n\nThe syntax Elixir provides for type specifications is similar to [the one in Erlang](https://www.erlang.org/doc/reference_manual/typespec.html). Most of the built-in types provided in Erlang (for example, `pid()`) are expressed in the same way: `pid()` (or simply `pid`). Parameterized types (such as `list(integer)`) are supported as well and so are remote types (such as [`Enum.t()`](`t:Enum.t/0`)). Integers and atom literals are allowed as types (for example, `1`, `:atom`, or `false`). All other types are built out of unions of predefined types. Some types can also be declared using their syntactical notation, such as `[type]` for lists, `{type1, type2, ...}` for tuples and `<<_ * _>>` for binaries.\n\nThe notation to represent the union of types is the pipe `|`. For example, the typespec `type :: atom() | pid() | tuple()` creates a type `type` that can be either an `atom`, a `pid`, or a `tuple`. This is usually called a [sum type](https://en.wikipedia.org/wiki/Tagged_union) in other languages\n\n> #### Differences with set-theoretic types {: .warning}\n>\n> While they do share some similarities, the types below do not map one-to-one\n> to the new types from the set-theoretic type system.\n>\n> For example, there is no plan to support subsets of the `integer()` type such\n> as positive, ranges or literals.\n>\n> Furthermore, set-theoretic types support the full range of set operations,\n> including intersections and negations.\n\n### Basic types\n\n    type ::\n          any()                     # the top type, the set of all terms\n          | none()                  # the bottom type, contains no terms\n          | atom()\n          | map()                   # any map\n          | pid()                   # process identifier\n          | port()                  # port identifier\n          | reference()\n          | tuple()                 # tuple of any size\n\n                                    ## Numbers\n          | float()\n          | integer()\n          | neg_integer()           # ..., -3, -2, -1\n          | non_neg_integer()       # 0, 1, 2, 3, ...\n          | pos_integer()           # 1, 2, 3, ...\n\n                                                                          ## Lists\n          | list(type)                                                    # proper list ([]-terminated)\n          | nonempty_list(type)                                           # non-empty proper list\n          | maybe_improper_list(content_type, termination_type)           # proper or improper list\n          | nonempty_improper_list(content_type, termination_type)        # improper list\n          | nonempty_maybe_improper_list(content_type, termination_type)  # non-empty proper or improper list\n\n          | Literals                # Described in section \"Literals\"\n          | BuiltIn                 # Described in section \"Built-in types\"\n          | Remotes                 # Described in section \"Remote types\"\n          | UserDefined             # Described in section \"User-defined types\"\n\n### Literals\n\nThe following literals are also supported in typespecs:\n\n    type ::                               ## Atoms\n          :atom                           # atoms: :foo, :bar, ...\n          | true | false | nil            # special atom literals\n\n                                          ## Bitstrings\n          | <<>>                          # empty bitstring\n          | <<_::size>>                   # size is 0 or a positive integer\n          | <<_::_*unit>>                 # unit is an integer from 1 to 256\n          | <<_::size, _::_*unit>>\n\n                                          ## (Anonymous) Functions\n          | (-> type)                     # zero-arity, returns type\n          | (type1, type2 -> type)        # two-arity, returns type\n          | (... -> type)                 # any arity, returns type\n\n                                          ## Integers\n          | 1                             # integer\n          | 1..10                         # integer from 1 to 10\n\n                                          ## Lists\n          | [type]                        # list with any number of type elements\n          | []                            # empty list\n          | [...]                         # shorthand for nonempty_list(any())\n          | [type, ...]                   # shorthand for nonempty_list(type)\n          | [key: value_type]             # keyword list with optional key :key of value_type\n\n                                                  ## Maps\n          | %{}                                   # empty map\n          | %{key: value_type}                    # map with required key :key of value_type\n          | %{key_type => value_type}             # map with required pairs of key_type and value_type\n          | %{required(key_type) => value_type}   # map with required pairs of key_type and value_type\n          | %{optional(key_type) => value_type}   # map with optional pairs of key_type and value_type\n          | %SomeStruct{}                         # struct with all fields of any type\n          | %SomeStruct{key: value_type}          # struct with required key :key of value_type\n\n                                          ## Tuples\n          | {}                            # empty tuple\n          | {:ok, type}                   # two-element tuple with an atom and any type\n\n### Built-in types\n\nThe following types are also provided by Elixir as shortcuts on top of the basic and literal types described above.\n\nBuilt-in type           | Defined as\n:---------------------- | :---------\n`term()`                | `any()`\n`arity()`               | `0..255`\n`as_boolean(t)`         | `t`\n`binary()`              | `<<_::_*8>>`\n`nonempty_binary()`     | `<<_::8, _::_*8>>`\n`bitstring()`           | `<<_::_*1>>`\n`nonempty_bitstring()`  | `<<_::1, _::_*1>>`\n`boolean()`             | `true` \\| `false`\n`byte()`                | `0..255`\n`char()`                | `0..0x10FFFF`\n`charlist()`            | `[char()]`\n`nonempty_charlist()`   | `[char(), ...]`\n`fun()`                 | `(... -> any)`\n`function()`            | `fun()`\n`identifier()`          | `pid()` \\| `port()` \\| `reference()`\n`iodata()`              | `iolist()` \\| `binary()`\n`iolist()`              | `maybe_improper_list(byte() \\| binary() \\| iolist(), binary() \\| [])`\n`keyword()`             | `[{atom(), any()}]`\n`keyword(t)`            | `[{atom(), t}]`\n`list()`                | `[any()]`\n`nonempty_list()`       | `nonempty_list(any())`\n`maybe_improper_list()` | `maybe_improper_list(any(), any())`\n`nonempty_maybe_improper_list()` | `nonempty_maybe_improper_list(any(), any())`\n`mfa()`                 | `{module(), atom(), arity()}`\n`module()`              | `atom()`\n`no_return()`           | `none()`\n`node()`                | `atom()`\n`number()`              | `integer()` \\| `float()`\n`struct()`              | `%{:__struct__ => atom(), optional(atom()) => any()}`\n`timeout()`             | `:infinity` \\| `non_neg_integer()`\n\n`as_boolean(t)` exists to signal users that the given value will be treated as a boolean, where `nil` and `false` will be evaluated as `false` and everything else is `true`. For example, `Enum.filter/2` has the following specification: `filter(t, (element -> as_boolean(term))) :: list`.\n\n### Remote types\n\nAny module is also able to define its own types and the modules in Elixir are no exception. For example, the `Range` module defines a `t/0` type that represents a range: this type can be referred to as `t:Range.t/0`. In a similar fashion, a string is `t:String.t/0`, and so on.\n\n### Maps\n\nThe key types in maps are allowed to overlap, and if they do, the leftmost key takes precedence.\nA map value does not belong to this type if it contains a key that is not in the allowed map keys.\n\nIf you want to denote that keys that were not previously defined in the map are allowed,\nit is common to end a map type with `optional(any) => any`.\n\nNote that the syntactic representation of `map()` is `%{optional(any) => any}`, not `%{}`. The notation `%{}` specifies the singleton type for the empty map.\n\n### Keyword Lists\n\nBeyond `keyword()` and `keyword(t)`, it can be helpful to compose a spec for an expected keyword list.\nFor example:\n\n```elixir\n@type option :: {:name, String.t} | {:max, pos_integer} | {:min, pos_integer}\n@type options :: [option()]\n```\n\nThis makes it clear that only these options are allowed, none are required, and order does not matter.\n\nIt also allows composition with existing types.\nFor example:\n\n```elixir\n@type option :: {:my_option, String.t()} | GenServer.option()\n\n@spec start_link([option()]) :: GenServer.on_start()\ndef start_link(opts) do\n  {my_opts, gen_server_opts} = Keyword.split(opts, [:my_option])\n  GenServer.start_link(__MODULE__, my_opts, gen_server_opts)\nend\n```\n\nThe following spec syntaxes are equivalent:\n\n```elixir\n@type options :: [{:name, String.t} | {:max, pos_integer} | {:min, pos_integer}]\n\n@type options :: [name: String.t, max: pos_integer, min: pos_integer]\n```\n\n### User-defined types\n\nThe `@type`, `@typep`, and `@opaque` module attributes can be used to define new types:\n\n    @type type_name :: type\n    @typep type_name :: type\n    @opaque type_name :: type\n\nA type defined with `@typep` is private. An opaque type, defined with `@opaque` is a type where the internal structure of the type will not be visible, but the type is still public.\n\nTypes can be parameterized by defining variables as parameters; these variables can then be used to define the type.\n\n    @type dict(key, value) :: [{key, value}]\n\n## Defining a specification\n\nA specification for a function can be defined as follows:\n\n    @spec function_name(type1, type2) :: return_type\n\nGuards can be used to restrict type variables given as arguments to the function.\n\n    @spec function(arg) :: [arg] when arg: atom\n\nIf you want to specify more than one variable, you separate them by a comma.\n\n    @spec function(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer\n\nType variables with no restriction can also be defined using `var`.\n\n    @spec function(arg) :: [arg] when arg: var\n\nThis guard notation only works with `@spec`, `@callback`, and `@macrocallback`.\n\nYou can also name your arguments in a typespec using `arg_name :: arg_type` syntax. This is particularly useful in documentation as a way to differentiate multiple arguments of the same type (or multiple elements of the same type in a type definition):\n\n    @spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer\n    @type color :: {red :: integer, green :: integer, blue :: integer}\n\nSpecifications can be overloaded, just like ordinary functions.\n\n    @spec function(integer) :: atom\n    @spec function(atom) :: integer\n\n## Behaviours\n\nBehaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*).\n\nA behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This \"interface\" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a \"server\" process will likely want to implement from the specific parts such as the actions that this server process has to perform.\n\nSay we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).\n\nWe can create a `Parser` behaviour:\n\n```elixir\ndefmodule Parser do\n  @doc \"\"\"\n  Parses a string.\n  \"\"\"\n  @callback parse(String.t) :: {:ok, term} | {:error, atom}\n\n  @doc \"\"\"\n  Lists all supported file extensions.\n  \"\"\"\n  @callback extensions() :: [String.t]\nend\n```\n\nAs seen in the example above, defining a callback is a matter of defining a specification for that callback, made of:\n\n  * the callback name (`parse` or `extensions` in the example)\n  * the arguments that the callback must accept (`String.t`)\n  * the *expected* type of the callback return value\n\nModules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above.\n\n### Implementing behaviours\n\nImplementing a behaviour is straightforward:\n\n```elixir\ndefmodule JSONParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some json \" <> str} # ... parse JSON\n\n  @impl Parser\n  def extensions, do: [\".json\"]\nend\n```\n\n```elixir\ndefmodule CSVParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some csv \" <> str} # ... parse CSV\n\n  @impl Parser\n  def extensions, do: [\".csv\"]\nend\n```\n\nIf a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.\n\nFurthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.\n\n```elixir\ndefmodule BADParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse, do: {:ok, \"something bad\"}\n\n  @impl Parser\n  def extensions, do: [\"bad\"]\nend\n```\n\nThis code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.\nYou can read more about `@impl` in the [module documentation](`Module#module-impl`).\n\n### Using behaviours\n\nBehaviours are useful because you can pass modules around as arguments and you can then *call back* to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:\n\n```elixir\n@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}\ndef parse_path(filename, parsers) do\n  with {:ok, ext} <- parse_extension(filename),\n       {:ok, parser} <- find_parser(ext, parsers),\n       {:ok, contents} <- File.read(filename) do\n    parser.parse(contents)\n  end\nend\n\ndefp parse_extension(filename) do\n  case Path.extname(filename) do\n    \"\" -> {:error, :no_extension}\n    ext -> {:ok, ext}\n  end\nend\n\ndefp find_parser(ext, parsers) do\n  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do\n    {:ok, parser}\n  else\n    {:error, :no_matching_parser}\n  end\nend\n```\n\nYou could also invoke any parser directly: `CSVParser.parse(...)`.\n\nNote you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.\n\n### Optional callbacks\n\nOptional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.\n\n> ### Unloaded modules {: .warning}\n>\n> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.\n\nOptional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:\n\n    defmodule MyBehaviour do\n      @callback vital_fun() :: any\n      @callback non_vital_fun() :: any\n      @macrocallback non_vital_macro(arg :: any) :: Macro.t\n      @optional_callbacks non_vital_fun: 0, non_vital_macro: 1\n    end\n\nOne example of optional callback in Elixir's standard library is `c:GenServer.format_status/1`.\n\n### Inspecting behaviours\n\nThe `@callback` and `@optional_callbacks` attributes are used to create a `behaviour_info/1` function available on the defining module. This function can be used to retrieve the callbacks and optional callbacks defined by that module.\n\nFor example, for the `MyBehaviour` module defined in \"Optional callbacks\" above:\n\n    MyBehaviour.behaviour_info(:callbacks)\n    #=> [vital_fun: 0, \"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n    MyBehaviour.behaviour_info(:optional_callbacks)\n    #=> [\"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n\nWhen using `iex`, the `IEx.Helpers.b/1` helper is also available.\n\n## Pitfalls\n\nThere are some known pitfalls when using typespecs, they are documented next.\n\n## The `string()` type\n\nElixir discourages the use of the `string()` type. The `string()` type refers to Erlang strings, which are known as \"charlists\" in Elixir. They do not refer to Elixir strings, which are UTF-8 encoded binaries. To avoid confusion, if you attempt to use the type `string()`, Elixir will emit a warning. You should use `charlist()`, `nonempty_charlist()`, `binary()` or `String.t()` accordingly, or any of the several literal representations for these types.\n\nNote that `String.t()` and `binary()` are equivalent to analysis tools. Although, for those reading the documentation, `String.t()` implies it is a UTF-8 encoded binary.\n\n## Functions which raise an error\n\nTypespecs do not need to indicate that a function can raise an error; any function can fail any time if given invalid input.\nIn the past, the Elixir standard library sometimes used `no_return()` to indicate this, but these usages have been removed.\n\nThe `no_return()` type also should not be used for functions which do return but whose purpose is a \"side effect\", such as `IO.puts/1`.\nIn these cases, the expected return type is `:ok`.\n\nInstead, `no_return()` should be used as the return type for functions which can never return a value.\nThis includes functions which loop forever calling `receive`, or which exist specifically to raise an error, or which shut down the VM.\n",".cursorrules (elixir-engineer-guidelines-cursorrules-prompt-file.mdc)":"---\ndescription: \"Cursor rules for Elixir development with engineer guidelines.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: \nElixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n\nWhere:\n\ntype: One of the following:\n\nscope (optional): A noun describing a section of the codebase (e.g., fluxcd, deployment).\n\ndescription: A brief summary of the change in present tense.\n\nbody (optional): A more detailed explanation of the change.\n\nfooter (optional): One or more footers in the following format:\n"},"items":[{"name":"compatibility-and-deprecations.md","path":"lib/elixir/pages/references/compatibility-and-deprecations.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/compatibility-and-deprecations.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Compatibility and deprecations\n\nElixir is versioned according to a vMAJOR.MINOR.PATCH schema.\n\nElixir is currently at major version v1. A new backwards compatible minor release happens every 6 months. Patch releases are not scheduled and are made whenever there are bug fixes or security patches.\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.21           | Development\n1.20           | Bug fixes and security patches\n1.19           | Security patches only\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann) and on the [GitHub releases page](https://github.com/elixir-lang/elixir/releases).\n\nYou may also see [all releases](https://github.com/elixir-lang/elixir/releases) and [consult all disclosed vulnerabilities](https://github.com/elixir-lang/elixir/security) on GitHub.\n\nThere are currently no plans for a major v2 release.\n\n## Between non-major Elixir versions\n\nElixir minor and patch releases are backwards compatible: well-defined behaviors and documented APIs in a given version will continue working on future versions.\n\nAlthough we expect the vast majority of programs to remain compatible over time, it is impossible to guarantee that no future change will break any program. Under some unlikely circumstances, we may introduce changes that break existing code:\n\n  * Security: a security issue in the implementation may arise whose resolution requires backwards incompatible changes. We reserve the right to address such security issues.\n\n  * Bugs: if an API has undesired behavior, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.\n\n  * Compiler front-end: improvements may be done to the compiler, introducing new warnings for ambiguous modes and providing more detailed error messages. Those can lead to compilation errors (when running with `--warnings-as-errors`) or tooling failures when asserting on specific error messages (although one should avoid such). We reserve the right to do such improvements.\n\n  * Imports: new functions may be added to the `Kernel` module, which is auto-imported. They may collide with local functions defined in your modules. Collisions can be resolved in a backwards compatible fashion using `import Kernel, except: [...]` with a list of all functions you don't want to be imported from `Kernel`. We reserve the right to do such additions.\n\nIn order to continue evolving the language without introducing breaking changes, Elixir will rely on deprecations to demote certain practices and promote new ones. Our deprecation policy is outlined in the [\"Deprecations\" section](#deprecations).\n\nThe only exception to the compatibility guarantees above are experimental features, which will be explicitly marked as such, and do not provide any compatibility guarantee until they are stabilized.\n\n## Between Elixir and Erlang/OTP\n\nErlang/OTP versioning is independent from the versioning of Elixir. Erlang releases a new major version yearly. Our goal is to support the last three Erlang major versions by the time Elixir is released. The compatibility table is shown below.\n\nElixir version | Supported Erlang/OTP versions\n:------------- | :-------------------------------\n1.21           | 27 - 29\n1.20           | 27 - 29\n1.19           | 26 - 28\n1.18           | 25 - 27\n1.17           | 25 - 27\n1.16           | 24 - 26\n1.15           | 24 - 26\n1.14           | 23 - 25 (and Erlang/OTP 26 from v1.14.5)\n1.13           | 22 - 24 (and Erlang/OTP 25 from v1.13.4)\n1.12           | 22 - 24\n1.11           | 21 - 23 (and Erlang/OTP 24 from v1.11.4)\n1.10           | 21 - 22 (and Erlang/OTP 23 from v1.10.3)\n1.9            | 20 - 22\n1.8            | 20 - 22\n1.7            | 19 - 22\n1.6            | 19 - 20 (and Erlang/OTP 21 from v1.6.6)\n1.5            | 18 - 20\n1.4            | 18 - 19 (and Erlang/OTP 20 from v1.4.5)\n1.3            | 18 - 19\n1.2            | 18 - 18 (and Erlang/OTP 19 from v1.2.6)\n1.1            | 17 - 18\n1.0            | 17 - 17 (and Erlang/OTP 18 from v1.0.5)\n\nElixir may add compatibility to new Erlang/OTP versions on patch releases, such as support for Erlang/OTP 20 in v1.4.5. Those releases are made for convenience and typically contain the minimum changes for Elixir to run without errors, if any changes are necessary. Only the next minor release, in this case v1.5.0, effectively leverages the new features provided by the latest Erlang/OTP release.\n\n## Deprecations\n\n### Policy\n\nElixir deprecations happen in 3 steps:\n\n  1. The feature is soft-deprecated. It means both CHANGELOG and documentation must list the feature as deprecated but no warning is effectively emitted by running the code. There is no requirement to soft-deprecate a feature.\n\n  2. The feature is effectively deprecated by emitting warnings on usage. This is also known as hard-deprecation. In order to deprecate a feature, the proposed alternative MUST exist for AT LEAST THREE minor versions. For example, `Enum.uniq/2` was soft-deprecated in favor of `Enum.uniq_by/2` in Elixir v1.1. This means a deprecation warning may only be emitted by Elixir v1.4 or later.\n\n  3. The feature is removed. This can only happen on major releases. This means deprecated features in Elixir v1.x shall only be removed by Elixir v2.x.\n\n### Table of deprecations\n\nThe first column is the version the feature was hard deprecated. The second column shortly describes the deprecated feature and the third column explains the replacement and from which the version the replacement is available from.\n\nVersion | Deprecated feature                                  | Replaced by (available since)\n:-------| :-------------------------------------------------- | :---------------------------------------------------------------\n[v1.21] | `Macro.Env.fetch_alias/2` (and `fetch_macro_alias`) | `Macro.Env.expand_alias/4` (v1.17)\n[v1.20] | `<<x::size(y)>>` in patterns without `^`            | `<<x::size(^y)>>` (v1.15)\n[v1.20] | `File.stream!(path, modes, lines_or_bytes)`         | `File.stream!(path, lines_or_bytes, modes)` (v1.16)\n[v1.20] | `Kernel.ParallelCompiler.async/1`                   | `Kernel.ParallelCompiler.pmap/2` (v1.16)\n[v1.20] | `Logger.*_backend` functions                        | The `LoggerBackends` module from [`:logger_backends`](https://hex.pm/packages/logger_backends) package\n[v1.20] | `Logger.enable/1` and `Logger.disable/1`            | `Logger.put_process_level/2` and `Logger.delete_process_level/1` respectively (v1.15)\n[v1.19] | CLI configuration in `def project` inside `mix.exs` | Moving it to `def cli` (v1.14)\n[v1.19] | Using `,` to separate tasks in `mix do`             | Using `+` (v1.14)\n[v1.19] | `Logger`'s `:backends` configuration                | `Logger`'s `:default_handler` configuration (v1.15)\n[v1.19] | Passing a callback to `File.cp/3`, `File.cp!/3`, `File.cp_r/3`, and `File.cp_r!/3` | The `:on_conflict` option (v1.14)\n[v1.18] | `<%#` in EEx                                        | `<%!--` (v1.14) or `<% #` (v1.0)\n[v1.18] | `EEx.Engine.handle_text/2` callback in EEx          | `c:EEx.Engine.handle_text/3` (v1.14)\n[v1.18] | Returning a 2-arity function from `Enumerable.slice/1` | Returning a 3-arity function (v1.14)\n[v1.18] | Ranges with negative steps in `Range.new/2`         | Explicit steps in ranges (v1.11)\n[v1.18] | `Tuple.append/2`                                    | `Tuple.insert_at/3` (v1.0)\n[v1.18] | `mix cmd --app APP`                                 | `mix do --app APP` (v1.14)\n[v1.18] | `List.zip/1`                                        | `Enum.zip/1` (v1.0)\n[v1.18] | `Module.eval_quoted/3`                              | `Code.eval_quoted/3` (v1.0)\n[v1.17] | Single-quoted charlists (`'foo'`)                   | `~c\"foo\"` (v1.0)\n[v1.17] | `left..right` in patterns and guards                | `left..right//step` (v1.11)\n[v1.17] | `ExUnit.Case.register_test/4`                       | `register_test/6` (v1.10)\n[v1.17] | `:all` in `IO.read/2` and `IO.binread/2`            | `:eof` (v1.13)\n[v1.16] | `~R/.../`                                           | `~r/.../` (v1.0)\n[v1.16] | Ranges with negative steps in `Enum.slice/2`        | Explicit steps in ranges (v1.11)\n[v1.16] | Ranges with negative steps in `String.slice/2`      | Explicit steps in ranges (v1.11)\n[v1.15] | `Calendar.ISO.day_of_week/3`                        | `Calendar.ISO.day_of_week/4` (v1.11)\n[v1.15] | `Exception.exception?/1`                            | `Kernel.is_exception/1` (v1.11)\n[v1.15] | `Regex.regex?/1`                                    | `Kernel.is_struct/2` (`Kernel.is_struct(term, Regex)`) (v1.11)\n[v1.15] | `Logger.warn/2`                                     | `Logger.warning/2` (v1.11)\n[v1.14] | `use Bitwise`                                       | `import Bitwise` (v1.0)\n[v1.14] | `~~~/1`                                             | `bnot/1` (v1.0)\n[v1.14] | `Application.get_env/3` and similar in module body  | `Application.compile_env/3` (v1.10)\n[v1.14] | Compiled patterns in `String.starts_with?/2`        | Pass a list of strings instead (v1.0)\n[v1.14] | `Mix.Tasks.Xref.calls/1`                            | Compilation tracers (outlined in `Code`) (v1.10)\n[v1.14] | `$levelpad` in Logger                               | *None*\n[v1.14] | `<\\|>` as a custom operator                         | Another custom operator (v1.0)\n[v1.13] | `!` and `!=` in Version requirements                | `~>` or `>=` (v1.0)\n[v1.13] | `Mix.Config`                                        | `Config` (v1.9)\n[v1.13] | `:strip_beam` config to `mix escript.build`         | `:strip_beams` (v1.9)\n[v1.13] | `Macro.to_string/2`                                 | `Macro.to_string/1` (v1.0)\n[v1.13] | `System.get_pid/0`                                  | `System.pid/0` (v1.9)\n[v1.12] | `^^^/2`                                             | `bxor/2` (v1.0)\n[v1.12] | `@foo()` to read module attributes                  | Remove the parenthesis (v1.0)\n[v1.12] | `use EEx.Engine`                                    | Explicitly delegate to EEx.Engine instead (v1.0)\n[v1.12] | `:xref` compiler in Mix                             | Nothing (it always runs as part of the compiler now)\n[v1.11] | `Mix.Project.compile/2`                             | `Mix.Task.run(\"compile\", args)` (v1.0)\n[v1.11] | `Supervisor.Spec.worker/3` and `Supervisor.Spec.supervisor/3` | The new child specs outlined in `Supervisor` (v1.5)\n[v1.11] | `Supervisor.start_child/2` and `Supervisor.terminate_child/2` | `DynamicSupervisor` (v1.6)\n[v1.11] | `System.stacktrace/0`                               | `__STACKTRACE__` in `try/catch/rescue` (v1.7)\n[v1.10] | `Code.ensure_compiled?/1`                           | `Code.ensure_compiled/1` (v1.0)\n[v1.10] | `Code.load_file/2`                                  | `Code.require_file/2` (v1.0) or `Code.compile_file/2` (v1.7)\n[v1.10] | `Code.loaded_files/0`                               | `Code.required_files/0` (v1.7)\n[v1.10] | `Code.unload_file/1`                                | `Code.unrequire_files/1` (v1.7)\n[v1.10] | Passing non-chardata to `Logger.log/2`              | Explicitly convert to string with `to_string/1` (v1.0)\n[v1.10] | `:compile_time_purge_level` in `Logger` app environment | `:compile_time_purge_matching` in `Logger` app environment (v1.7)\n[v1.10] | `Supervisor.Spec.supervise/2`                       | The new child specs outlined in `Supervisor` (v1.5)\n[v1.10] | `:simple_one_for_one` strategy in `Supervisor`      | `DynamicSupervisor` (v1.6)\n[v1.10] | `:restart` and `:shutdown` in `Task.Supervisor.start_link/1` | `:restart` and `:shutdown` in `Task.Supervisor.start_child/3` (v1.6)\n[v1.9]  | Enumerable keys in `Map.drop/2`, `Map.split/2`, and `Map.take/2` | Call `Enum.to_list/1` on the second argument before hand (v1.0)\n[v1.9]  | `Mix.Project.load_paths/1`                          | `Mix.Project.compile_path/1` (v1.0)\n[v1.9]  | Passing `:insert_replaced` to `String.replace/4`    | Use `:binary.replace/4` (v1.0)\n[v1.8]  | Passing a non-empty list to `Collectable.into/1`    | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `:into` in `for/1`      | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `Enum.into/2`           | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Time units in its plural form, such as: `:seconds`, `:milliseconds`, and the like | Use the singular form, such as: `:second`, `:millisecond`, and so on (v1.4)\n[v1.8]  | `Inspect.Algebra.surround/3`                        | `Inspect.Algebra.concat/2` and `Inspect.Algebra.nest/2` (v1.0)\n[v1.8]  | `Inspect.Algebra.surround_many/6`                   | `Inspect.Algebra.container_doc/6` (v1.6)\n[v1.9]  | `--detached` in `Kernel.CLI`                        | `--erl \"-detached\"` (v1.0)\n[v1.8]  | `Kernel.ParallelCompiler.files/2`                   | `Kernel.ParallelCompiler.compile/2` (v1.6)\n[v1.8]  | `Kernel.ParallelCompiler.files_to_path/2`           | `Kernel.ParallelCompiler.compile_to_path/2` (v1.6)\n[v1.8]  | `Kernel.ParallelRequire.files/2`                    | `Kernel.ParallelCompiler.require/2` (v1.6)\n[v1.8]  | Returning `{:ok, contents}` or `:error` from `Mix.Compilers.Erlang.compile/6`'s callback | Return `{:ok, contents, warnings}` or `{:error, errors, warnings}` (v1.6)\n[v1.8]  | `System.cwd/0` and `System.cwd!/0`                  | `File.cwd/0` and `File.cwd!/0` respectively (v1.0)\n[v1.7]  | `Code.get_docs/2`                                   | `Code.fetch_docs/1` (v1.7)\n[v1.7]  | `Enum.chunk/2,3,4`                                  | `Enum.chunk_every/2` and [`Enum.chunk_every/3,4`](`Enum.chunk_every/4`) (v1.5)\n[v1.7]  | Calling `super/1` in`GenServer` callbacks           | Implementing the behaviour explicitly without calling `super/1` (v1.0)\n[v1.7]  | [`not left in right`](`in/2`)                | [`left not in right`](`in/2`) (v1.5)\n[v1.7]  | `Registry.start_link/3`                             | `Registry.start_link/1` (v1.5)\n[v1.7]  | `Stream.chunk/2,3,4`                                | `Stream.chunk_every/2` and [`Stream.chunk_every/3,4`](`Stream.chunk_every/4`) (v1.5)\n[v1.6]  | `Enum.partition/2`                                  | `Enum.split_with/2` (v1.4)\n[v1.6]  | `Macro.unescape_tokens/1,2`                         | Use `Enum.map/2` to traverse over the arguments (v1.0)\n[v1.6]  | `Module.add_doc/6`                                  | [`@doc`](`Module`) module attribute (v1.0)\n[v1.6]  | `Range.range?/1`                                    | Pattern match on [`_.._`](`../2`) (v1.0)\n[v1.5]  | `()` to mean `nil`                                  | `nil` (v1.0)\n[v1.5]  | `char_list/0` type                                  | `t:charlist/0` type (v1.3)\n[v1.5]  | `Atom.to_char_list/1`                               | `Atom.to_charlist/1` (v1.3)\n[v1.5]  | `Enum.filter_map/3`                                 | `Enum.filter/2` + `Enum.map/2` or `for/1` comprehensions (v1.0)\n[v1.5]  | `Float.to_char_list/1`                              | `Float.to_charlist/1` (v1.3)\n[v1.5]  | `GenEvent` module                                   | `Supervisor` and `GenServer` (v1.0)\n[v1.5]  | `<%=` in middle and end expressions in `EEx`        | Use `<%` (`<%=` is allowed only in start expressions) (v1.0)\n[v1.5]  | `:as_char_lists` value in `t:Inspect.Opts.t/0` type | `:as_charlists` value (v1.3)\n[v1.5]  | `:char_lists` key in `t:Inspect.Opts.t/0` type      | `:charlists` key (v1.3)\n[v1.5]  | `Integer.to_char_list/1,2`                          | `Integer.to_charlist/1` and `Integer.to_charlist/2` (v1.3)\n[v1.5]  | `to_char_list/1`                                    | `to_charlist/1` (v1.3)\n[v1.5]  | `List.Chars.to_char_list/1`                         | `List.Chars.to_charlist/1` (v1.3)\n[v1.5]  | `@compile {:parse_transform, _}` in `Module`        | *None*\n[v1.5]  | `Stream.filter_map/3`                               | `Stream.filter/2` + `Stream.map/2` (v1.0)\n[v1.5]  | `String.ljust/3` and `String.rjust/3`               | Use `String.pad_leading/3` and `String.pad_trailing/3` with a binary padding (v1.3)\n[v1.5]  | `String.lstrip/1` and `String.rstrip/1`             | `String.trim_leading/1` and `String.trim_trailing/1` (v1.3)\n[v1.5]  | `String.lstrip/2` and `String.rstrip/2`             | Use `String.trim_leading/2` and `String.trim_trailing/2` with a binary as second argument (v1.3)\n[v1.5]  | `String.strip/1` and `String.strip/2`               | `String.trim/1` and `String.trim/2` (v1.3)\n[v1.5]  | `String.to_char_list/1`                             | `String.to_charlist/1` (v1.3)\n[v1.4]  | Anonymous functions with no expression after `->`   | Use an expression or explicitly return `nil` (v1.0)\n[v1.4]  | Support for making [private functions](`defp/2`) overridable | Use [public functions](`def/2`) (v1.0)\n[v1.4]  | Variable used as function call                      | Use parentheses (v1.0)\n[v1.4]  | `Access.key/1`                                      | `Access.key/2` (v1.3)\n[v1.4]  | `Behaviour` module                                  | `@callback` module attribute (v1.0)\n[v1.4]  | `Enum.uniq/2`                                       | `Enum.uniq_by/2` (v1.2)\n[v1.4]  | `Float.to_char_list/2`                              | `:erlang.float_to_list/2` (Erlang/OTP 17)\n[v1.4]  | `Float.to_string/2`                                 | `:erlang.float_to_binary/2` (Erlang/OTP 17)\n[v1.4]  | `HashDict` module                                   | `Map` (v1.2)\n[v1.4]  | `HashSet` module                                    | `MapSet` (v1.1)\n[v1.4]  | `IEx.Helpers.import_file/2`                         | `IEx.Helpers.import_file_if_available/1` (v1.3)\n[v1.4]  | `Mix.Utils.camelize/1`                              | `Macro.camelize/1` (v1.2)\n[v1.4]  | `Mix.Utils.underscore/1`                            | `Macro.underscore/1` (v1.2)\n[v1.4]  |  Multi-letter aliases in `OptionParser`             | Use single-letter aliases (v1.0)\n[v1.4]  | `Set` module                                        | `MapSet` (v1.1)\n[v1.4]  | `Stream.uniq/2`                                     | `Stream.uniq_by/2` (v1.2)\n[v1.3]  | `\\x{X*}` inside strings/sigils/charlists            | `\\uXXXX` or `\\u{X*}` (v1.1)\n[v1.3]  | `Dict` module                                       | `Keyword` (v1.0) or `Map` (v1.2)\n[v1.3]  | `:append_first` option in `defdelegate/2`           | Define the function explicitly (v1.0)\n[v1.3]  | Map/dictionary as 2nd argument in `Enum.group_by/3` | `Enum.reduce/3` (v1.0)\n[v1.3]  | `Keyword.size/1`                                    | `length/1` (v1.0)\n[v1.3]  | `Map.size/1`                                        | `map_size/1` (v1.0)\n[v1.3]  | `/r` option in `Regex`                              | `/U` (v1.1)\n[v1.3]  | `Set` behaviour                                     | `MapSet` data structure (v1.1)\n[v1.3]  | `String.valid_character?/1`                         | `String.valid?/1` (v1.0)\n[v1.3]  | `Task.find/2`                                       | Use direct message matching (v1.0)\n[v1.3]  | Non-map as 2nd argument in `URI.decode_query/2`     | Use a map (v1.0)\n[v1.2]  | `Dict` behaviour                                    | `Map` and `Keyword` (v1.0)\n[v1.1]  | `?\\xHEX`                                            | `0xHEX` (v1.0)\n[v1.1]  | `Access` protocol                                   | `Access` behaviour (v1.1)\n[v1.1]  | `as: true \\| false` in `alias/2` and `require/2`    | *None*\n\n[v1.1]: https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md#4-deprecations\n[v1.2]: https://github.com/elixir-lang/elixir/blob/v1.2/CHANGELOG.md#changelog-for-elixir-v12\n[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations\n[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations\n[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations\n[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations\n[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations\n[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations\n[v1.9]: https://github.com/elixir-lang/elixir/blob/v1.9/CHANGELOG.md#4-hard-deprecations\n[v1.10]: https://github.com/elixir-lang/elixir/blob/v1.10/CHANGELOG.md#4-hard-deprecations\n[v1.11]: https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#4-hard-deprecations\n[v1.12]: https://github.com/elixir-lang/elixir/blob/v1.12/CHANGELOG.md#4-hard-deprecations\n[v1.13]: https://github.com/elixir-lang/elixir/blob/v1.13/CHANGELOG.md#4-hard-deprecations\n[v1.14]: https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#4-hard-deprecations\n[v1.15]: https://github.com/elixir-lang/elixir/blob/v1.15/CHANGELOG.md#4-hard-deprecations\n[v1.16]: https://github.com/elixir-lang/elixir/blob/v1.16/CHANGELOG.md#4-hard-deprecations\n[v1.17]: https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md#4-hard-deprecations\n[v1.18]: https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md#4-hard-deprecations\n[v1.19]: https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md#4-hard-deprecations\n[v1.20]: https://github.com/elixir-lang/elixir/blob/v1.20/CHANGELOG.md#4-hard-deprecations\n[v1.21]: https://github.com/elixir-lang/elixir/blob/main/CHANGELOG.md#4-hard-deprecations\n","isInternal":false,"tokens":6598,"sizeBytes":21656},{"name":"gradual-set-theoretic-types.md","path":"lib/elixir/pages/references/gradual-set-theoretic-types.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/gradual-set-theoretic-types.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Gradual set-theoretic types\n\nElixir is in the process of incorporating set-theoretic types into the compiler. This document outlines the current stage of our implementation for this Elixir version. Elixir's type system is:\n\n  * **sound** - the inferred and assigned by the type system align with the behaviour of the program\n\n  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. However, instead of simply discarding all typing information, Elixir's `dynamic()` type works as a range. For example, if you write `dynamic(integer() or binary())`, Elixir's type system will still emit violations if none of those types are accepted. Furthermore, in the absence of `dynamic()`, Elixir's type system behaves as a static one\n\n  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)\n\nThe current milestone aims to infer types from existing programs and use them for type checking, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. User provided type signatures are planned for future releases. The underlying principles, theory, and roadmap of our work have been outlined in [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).\n\n## A gentle introduction\n\nTypes in Elixir are written using the type named followed by parentheses, such as `integer()` or `list(integer())`.\n\nThe basic types are:\n\n```elixir\natom()\nbinary()\nbitstring()\nempty_list()\ninteger()\nfloat()\nfunction()\nmap()\nnon_empty_list(elem_type, tail_type)\npid()\nport()\nreference()\ntuple()\n```\n\nMany of the types above can also be written more precisely. We will discuss their syntax in the next sections, but here are two examples:\n\n  * While `atom()` represents all atoms, the atom `:ok` can also be represented in the type system as `:ok`\n\n  * While `tuple()` represents all tuples, you can specify the type of a two-element tuple where the first element is the atom `:ok` and the second is an integer as `{:ok, integer()}`\n\nThere are also three special types: `none()` (represents an empty set), `term()` (represents all types), `dynamic()` (represents a range of the given types).\n\nGiven the types are set-theoretic, we can compose them using unions (`or`), intersections (`and`), and negations (`not`). For example, to say a function returns either atoms or integers, one could write: `atom() or integer()`.\n\nIntersections will find the elements in common between the operands. For example, `atom() and integer()`, which in this case is the empty set `none()`. You can combine intersections and negations to perform difference, for example, to say that a function expects all atoms, except `nil` (which is an atom), you could write: `atom() and not nil`.\n\nYou can find a complete reference in the [set-theoretic types cheatsheet](../cheatsheets/types-cheat.cheatmd).\n\n## The syntax of data types\n\nIn this section we will cover the syntax of all data types. At the moment, developers will interact with those types mostly through compiler warnings and diagnostics.\n\n### Broad types\n\nThese types are broad in that they cannot represent individual elements, only the whole set. For example, the numbers `1` and `42` are both represented by the type `integer()`.\n\nThey are: `binary()`, `bitstring()`, `integer()`, `float()`, `pid()`, `port()`, `reference()`.\n\nThe `binary()` type is a subtype of the less frequently used `bitstring()` type, as binaries are bitstrings where the number of bits is divisible by 8.\n\n### Atoms\n\nYou can represent all atoms as `atom()`. You can also represent each individual atom using their literal syntax. For instance, the atom `:foo` and `:hello_world` are also valid (distinct) types.\n\n`nil`, `true`, and `false` are also atoms and can be written as is. `boolean()` is a convenience type alias that represents `true or false`.\n\n### Tuples\n\nYou can represent all tuples as `tuple()`. Tuples may also be written using the curly brackets syntax, such as `{:ok, binary()}`.\n\nYou may use `...` at the end of the tuple to imply the overall size of the tuple is unknown. For example, the following tuple has at least two elements: `{:ok, binary(), ...}`.\n\n### Lists\n\nYou can represent all _proper_ lists as `list()`, which also includes the empty list.\n\nYou can also specify the type of the list element as argument. For example, `list(integer())` represents the values `[]` and `[1, 2, 3]`, but not `[1, \"two\", 3]`.\n\nInternally, Elixir represents the type `list(a)` as the union two distinct types, `empty_list()` and `non_empty_list(a)`. In other words, `list(integer())` is equivalent to `empty_list() or non_empty_list(integer())`.\n\n#### Improper lists\n\nWhile most developers will simply use `list(a)`, the type system can express all different representations of lists in Elixirby passing a second argument to `non_empty_list`, which represents the type of the tail.\n\nA proper list is one where the tail is the empty list itself. The type `non_empty_list(integer())` is equivalent to `non_empty_list(integer(), empty_list())`.\n\nIf the `tail_type` is anything but a list, then we have an improper list. For example, the value `[1, 2 | 3]` would have the type `non_empty_list(integer(), integer())`.\n\nIf you pass a list type as the tail, then the list type is merged into the element type. For example, `non_empty_list(integer(), list(binary()))` is the same as `non_empty_list(integer() or binary(), empty_list())`.\n\n### Maps\n\nYou can represent all maps as `map()`.\n\nMaps may also be written using their literal syntax:\n\n```elixir\n%{name: binary(), age: integer()}\n```\n\nwhich outlines a map with exactly two keys, `:name` and `:age`, and values of type `binary()` and `integer()` respectively. We say the map above is \"closed\": it only supports the keys explicitly defined. We can also mark a map as \"open\", by including `...` as its first element:\n\n```elixir\n%{..., name: binary(), age: integer()}\n```\n\nThe type above says the keys `:name` and `:age` must exist, with their respective types, but other keys may be present. The `map()` type is the same as `%{...}`. For the empty map, you may write `%{}`, although we recommend using `empty_map()` for clarity.\n\n#### Optional keys\n\nA key may be marked as optional using the `if_set/1` operation on its value type:\n\n```elixir\n%{name: binary(), age: if_set(integer())}\n```\n\nis a map that certainly has the `:name` key but it may have the `:age` key (and if it has such key, its value type is `integer()`).\n\nYou can also use `not_set()` to denote a key cannot be present:\n\n```elixir\n%{..., age: not_set()}\n```\n\nThe type above says the map may have any key, except the `:age` one. This is, for instance, the type returned by `Map.delete(map, :age)`.\n\n#### Domain types\n\nIn the examples above, all map keys were atoms, but we can also use other types as map keys. For example:\n\n```elixir\n# Closed map\n%{binary() or atom() => integer()}\n\n# Open map\n%{..., binary() or atom() => integer()}\n```\n\nCurrently, the type system only tracks the top of each individual type as the domain keys. For example, if you say:\n\n```elixir\n%{list(integer()) => integer(), list(binary()) => binary()}\n```\n\nThat's the same as specifying all lists:\n\n```elixir\n%{list() => integer() or binary()}\n```\n\nThe supported domain keys are `atom()`, `bitstring()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, and `tuple()`. In the case of maps, the `bitstring()` domain stores exclusively keys which are not binary. The ones which are `binary()` are stored under the `binary()` domain.\n\nFurthermore, it is important to note that domain keys are, by definition, optional. Whenever you have a `%{integer() => integer()}`and you try to fetch a key, we must assume the key may not exist (after all, it is not possible to store all integers as map keys as they are infinite).\n\n#### Mixed keys\n\nIt is also possible to mix domain and atom keys. For example, the following map says that all atom keys are of type `binary()`, except the `:root` key, which has type `integer()`:\n\n```elixir\n# Closed map\n%{atom() => binary(), root: integer()}\n\n# Open map\n%{..., atom() => binary(), root: integer()}\n```\n\nThe order of the keys is of increasing precision. `:root` is more precise than `atom()`, therefore it comes later. This mirrors the runtime semantics of maps, where duplicate keys override the value of earlier ones.\n\n### Functions\n\nYou can represent all functions as `function()`.  However, in practice, most functions are represented as arrows. For example, a function that receives an integer and return boolean would be written as `(integer() -> boolean())`. A function that receives two integers and return a string (i.e. a binary) would be written as `(integer(), integer() -> binary())`.\n\nWhen representing functions with multiple clauses, which may take different input types, we use intersections. For example, imagine the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nIf you give it an integer, it negates it. If you give it a boolean, it negates it.\n\nWe can say this function has the type `(integer() -> integer())` because it is capable of receiving an integer and returning an integer. In this case, `(integer() -> integer())` is a set that represents all functions that can receive an integer and return an integer. Even though this function can receive other arguments and return other values, it is still part of the `(integer() -> integer())` set.\n\nThis function also has the type `(boolean() -> boolean())`, because it also receives booleans and returns booleans. If you pass the function above to another function that expects `(boolean() -> boolean())`, type checking will succeed. Therefore, we can say the overall type of the function is `(integer() -> integer()) and (boolean() -> boolean())`. The intersection means the function belongs to both sets.\n\nAt this point, you may ask, why not a union? As a real-world example, take a t-shirt with green and yellow stripes. We can say the t-shirt belongs to the set of \"t-shirts with green color\". We can also say the t-shirt belongs to the set of \"t-shirts with yellow color\". Let's see the difference between unions and intersections:\n\n  * `(t_shirts_with_green() or t_shirts_with_yellow())` - contains t-shirts with either green or yellow, such as green, green and red, green and yellow, but also only yellow, yellow and red, etc.\n\n  * `(t_shirts_with_green() and t_shirts_with_yellow())` - contains t-shirts with both green and yellow (and maybe other colors)\n\nSince the t-shirt has both colors, we could say it belongs to the union of green and yellow t-shirts, but doing so would not capture the fact it is both green and yellow. Therefore it is more precise to say it belongs to the intersection of both sets. The same way that a function that goes from `(integer() -> integer())` and `(boolean() -> boolean())` is also an intersection. In practice, it is not useful to define the union of two functions in Elixir, so the compiler will point you to the right direction if you specify the wrong one.\n\n## The `dynamic()` type\n\nExisting Elixir programs do not have type declarations, but we still want to be able to type check them. This is done with the introduction of the `dynamic()` type.\n\nWhen Elixir sees the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nElixir type checks it as if the function had the type `(dynamic() -> dynamic())`. Then, based on patterns and guards, we can refine the value of the variable `x` to be `dynamic() and integer()` and `dynamic() and boolean()` for each clause respectively. We say `dynamic()` is a gradual type, which leads us to _gradual set-theoretic types_.\n\nThe simplest way to reason about `dynamic()` in Elixir is that it is a range of types. If you have a type `atom() or integer()`, the underlying code needs to work with both `atom() or integer()`. For example, if you call `Integer.to_string(var)`, and `var` has type `atom() or integer()`, the type system will emit a warning, because `Integer.to_string/1` does not accept atoms.\n\nHowever, by intersecting a type with `dynamic()`, we make the type gradual and therefore only a subset of the type needs to be valid. For instance, if you call `Integer.to_string(var)`, and `var` has type `dynamic() and (atom() or integer())`, the type system will not emit a warning, because `Integer.to_string/1` works with at least one of the types. For convenience, most programs will write `dynamic(atom() or integer())` instead of the intersection. They are equivalent.\n\nCompared to other gradually typed languages, the `dynamic()` type in Elixir is quite powerful: it restricts our program to certain types, via intersections, while still emitting warnings once it is certain the code will fail. This makes `dynamic()` an excellent tool for typing existing Elixir code with meaningful warnings.\n\nIf the user provides their own types, and those types are not `dynamic()`, then Elixir's type system behaves as a statically typed one. This brings us to one last property of dynamic types in Elixir: dynamic types are always at the root. For example, when you write a tuple of type `{:ok, dynamic()}`, Elixir will rewrite it to `dynamic({:ok, term()})`. While this has the downside that you cannot make part of a tuple/map/list gradual, only the whole tuple/map/list, it comes with the upside that dynamic is always explicitly at the root, making it harder to accidentally sneak `dynamic()` in a statically typed program.\n\n## Type inference\n\nType inference (or reconstruction) is the ability of a type system to automatically deduce, either partially or fully, the type of an expression at compile time. Type inference may occur at different levels. For example, many programming languages can automatically infer the types of variables, also known \"local type inference\", but not all can infer type signatures of functions.\n\nInferring type signatures comes with a series of trade-offs:\n\n  * Speed - type inference algorithms are often more computationally intensive than type checking algorithms.\n\n  * Expressiveness - in any given type system, the constructs that support inference are always a subset of those that can be type-checked. Therefore, if a programming language is restricted to fully reconstructed types, it is less expressive than a solely type checked counterpart.\n\n  * Incremental compilation - type inference complicates incremental compilation. If module A depends on module B, which depends on module C, a change to C may require the type signature in B to be reconstructed, which may then require A to be recomputed (and so on). This dependency chain may require large projects to explicitly add type signatures for stability and compilation efficiency.\n\n  * Cascading errors - when a user accidentally makes type errors or the code has conflicting assumptions, type inference may lead to less clear error messages as the type system tries to reconcile diverging type assumptions across code paths.\n\nOn the other hand, type inference offers the benefit of enabling type checking for functions and codebases without requiring the user to add type annotations. To balance these trade-offs, Elixir aims to provide type inference across dependencies: our goal is to infer the types of functions considering the current module, Elixir's standard library and your dependencies, while calls to modules within the same project are assumed to be `dynamic()`. Once types are inferred, then the whole project is type checked considering all modules and all types (inferred or otherwise).\n\nType inference in Elixir is best-effort: it doesn't guarantee it will find all possible type incompatibilities, only that it may find bugs where all combinations of a type _will_ fail, even in the absence of explicit type annotations. It is meant to be an efficient routine that brings developers some benefits of static typing, without requiring any effort from them and keeping the expressiveness of the language.\n\nIn the long term, Elixir developers who want static typing guarantees may explicitly add type signatures to their functions (see \"Roadmap\"). Any function with an explicit type signature will be typed checked against the user-provided annotations, as in other statically typed languages.\n\n### False positives\n\nElixir's type inference generally avoids emitting false positive type violations: which are warnings emitted by the type checker when there are no runtime errors. However, in some situations, those may happen and are documented below.\n\n#### `for`-comprehensions assume they may be executed zero, once, or multiple times\n\nFor comprehensions in Elixir assume they are executed at least once. Take this code:\n\n```elixir\ndef example(x, list) do\n  for _i <- list do\n    Atom.to_string(x)\n  end\n\n  x + 1\nend\n```\n\n`x + 1` will fail because it assumes `x` is an atom from the `Atom.to_string(x)` call, even though the function may raise no runtime error if `list` is an empty list. This is intentional, as it helps find discrepancies inside and outside comprehensions. You can address this by explicitly wrapping the comprehension in a `if list != [] do` block (or similar condition).\n\nSimilar, when using the `:reduce` option, Elixir assumes the list may be empty and therefore the accumulator must match the result type. Take this contrived example:\n\n```elixir\ndef example([_ | _] = list) do\n  Integer.to_string(\n    for i <- list, reduce: :unused do\n      _unused -> i * 2\n    end\n  )\nend\n```\n\nEven though the list is non-empty, for-comprehension always assumes the list can be empty, and the code above will fail because passing `:unused` to `Integer.to_string/1` is a typing violation (which will happen if list is empty). You fix this by making sure the accumulator matches the type of the comprehension body.\n\n#### Struct update syntax must be statically proven\n\nElixir will warn if you use the struct update syntax and it is not statically proven that the given value does not have said struct type. For example:\n\n```elixir\nuser = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\nEven though it is guaranteed at runtime that user is always a `User` struct. If the type system cannot prove it, it will emit a typing violation. This is how struct updates work by design. In such cases, you can address it by matching on the struct when the user variable is defined:\n\n```elixir\n%User{} = user = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\n## Roadmap\n\nAt this moment, Elixir implements type inference of all language constructs. The goal is to assess performance and collect feedback on the quality of error messages, before introducing user facing types.\n\nIf the results are satisfactory, the next milestone will include a mechanism for defining typed structs. Elixir programs frequently pattern match on structs, which reveals information about the struct fields, but it knows nothing about their respective types. By propagating types from structs and their fields throughout the program, we will increase the type system’s ability to find errors while further straining our type system implementation. Proposals including the required changes to the language surface will be sent to the community once we reach this stage.\n\nThe third milestone is to introduce set-theoretic type signatures for functions. Unfortunately, the existing Erlang Typespecs are not precise enough for set-theoretic types and they will be phased out of the language and have their postprocessing moved into a separate library once this stage concludes.\n\n## Resources\n\n  * (Paper) [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391)\n  * (Video) [\"The foundations of the Elixir type system\" by José Valim](https://youtu.be/giYbq4HmfGA)\n  * (Video) [\"Precision in type system design\" by José Valim](https://youtu.be/Ay-gnCqDw9o?t=102)\n\n## Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), and [Tidewave](https://tidewave.ai/).\n","isInternal":false,"tokens":4713,"sizeBytes":20641},{"name":"library-guidelines.md","path":"lib/elixir/pages/references/library-guidelines.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/library-guidelines.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Library guidelines\n\nThis document outlines general guidelines for those writing and publishing\nElixir libraries meant to be consumed by other developers.\n\n## Getting started\n\nYou can create a new Elixir library by running the `mix new` command:\n\n    $ mix new my_library\n\nThe project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.\n\nEvery project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.\n\nThe `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).\n\n## Publishing\n\nWriting code is only the first of many steps to publish a package. We strongly recommend developers to:\n\n  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).\n\n  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.\n\n  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.\n\n  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.\n\n  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports \"extra pages\", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.\n\n  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.\n\nProjects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).\n\n## Dependency handling\n\nWhen your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.\n\nKeep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).\n\nOn the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.\n\nIf you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.\n\n### Dependency Version Requirements\n\nWhen depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `\"~> x.y\"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.\n\nThe exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `\"~> 0.1.2\"` is a better default.\n\nA common mistake is to use a dependency in the format of `\"~> x.y.z\"` to express \"a version greater than `x.y.z`\". For example, if you are depending on `\"~> 1.2\"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `\"~> 1.2.1\"` to express that dependency, you are preventing users from upgrading to `\"1.3.0\"` or higher! Instead of `\"~> 1.2.1\"`, you should use `\"~> 1.2 and >= 1.2.1\"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.\n","isInternal":false,"tokens":1598,"sizeBytes":7200},{"name":"naming-conventions.md","path":"lib/elixir/pages/references/naming-conventions.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/naming-conventions.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Naming conventions\n\nThis document is a reference of the naming conventions in Elixir, from casing to punctuation characters.\n\nThe naming convention is, by definition, a subset of the Elixir syntax. A convention aims to\nfollow and set best practices for language and the community. If instead you want a complete reference into the Elixir syntax, beyond its conventions, see [the Syntax reference](syntax-reference.md).\n\n## Casing\n\nElixir developers must use `snake_case` when defining variables, function names, module attributes, and the like:\n\n    some_map = %{this_is_a_key: \"and a value\"}\n    is_map(some_map)\n\nAliases, commonly used as module names, are an exception as they must be capitalized and written in `CamelCase`, like `OptionParser`. For aliases, capital letters are kept in acronyms, like `ExUnit.CaptureIO` or `Mix.SCM`.\n\nAtoms can be written either in `:snake_case` or `:CamelCase`, although the convention is to use the snake case version throughout Elixir.\n\nGenerally speaking, filenames follow the `snake_case` convention of the module they define. For example, `MyApp` should be defined inside the `my_app.ex` file. However, this is only a convention. At the end of the day any filename can be used as they do not affect the compiled code in any way.\n\n## Underscore (`_foo`)\n\nElixir relies on underscores in different situations.\n\nFor example, a value that is not meant to be used must be assigned to `_` or to a variable starting with underscore:\n\n    iex> {:ok, _contents} = File.read(\"README.md\")\n\nFunction names may also start with an underscore. Such functions are never imported by default:\n\n    iex> defmodule Example do\n    ...>   def _wont_be_imported do\n    ...>     :oops\n    ...>   end\n    ...> end\n\n    iex> import Example\n    iex> _wont_be_imported()\n    ** (CompileError) iex:1: undefined function _wont_be_imported/0\n\nDue to this property, Elixir relies on functions starting with underscore to attach compile-time metadata to modules. Such functions are most often in the `__foo__` format. For example, every module in Elixir has an [`__info__/1`](`c:Module.__info__/1`) function:\n\n    iex> String.__info__(:functions)\n    [at: 2, capitalize: 1, chunk: 2, ...]\n\nElixir also includes five special forms that follow the double underscore format: `__CALLER__/0`, `__DIR__/0`, `__ENV__/0`and `__MODULE__/0` retrieve compile-time information about the current environment, while `__STACKTRACE__/0` retrieves the stacktrace for the current exception.\n\n## Trailing bang (`foo!`)\n\nA trailing bang (exclamation mark) signifies a function or macro where failure cases raise an exception. They most often exist as a \"raising variant\" of a function that returns `:ok`/`:error` tuples (or `nil`).\n\nOne example is `File.read/1` and `File.read!/1`. `File.read/1` will return a success or failure tuple, whereas `File.read!/1` will return a plain value or else raise an exception:\n\n    iex> File.read(\"file.txt\")\n    {:ok, \"file contents\"}\n    iex> File.read(\"no_such_file.txt\")\n    {:error, :enoent}\n\n    iex> File.read!(\"file.txt\")\n    \"file contents\"\n    iex> File.read!(\"no_such_file.txt\")\n    ** (File.Error) could not read file no_such_file.txt: no such file or directory\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n    case File.read(file) do\n      {:ok, body} -> # do something with the `body`\n      {:error, reason} -> # handle the error caused by `reason`\n    end\n\nHowever, if you expect the outcome to always be successful (for instance, if you expect the file always to exist), the bang variation can be more convenient and will raise a more helpful error message (than a failed pattern match) on failure.\n\nWhen thinking about failure cases, we are often thinking about semantic errors related to the operation being performed, such as failing to open a file or trying to fetch key from a map. Errors that come from invalid argument types, or similar, must always raise regardless if the function has a bang or not. In such cases, the exception is often an `ArgumentError` or a detailed `FunctionClauseError`:\n\n    iex(1)> File.read(123)\n    ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1\n\n        The following arguments were given to IO.chardata_to_string/1:\n\n            # 1\n            123\n\n        Attempted function clauses (showing 2 out of 2):\n\n            def chardata_to_string(string) when is_binary(string)\n            def chardata_to_string(list) when is_list(list)\n\nMore examples of paired functions: `Base.decode16/2` and `Base.decode16!/2`, `File.cwd/0` and `File.cwd!/0`. In some situations, you may have bang functions without a non-bang counterpart. They also imply the possibility of errors, such as: `Protocol.assert_protocol!/1` and `PartitionSupervisor.resize!/2`. This can be useful if you foresee the possibility of adding a non-raising variant in the future.\n\n## Trailing question mark (`foo?`)\n\nFunctions that return a boolean are named with a trailing question mark.\n\nExamples: `Keyword.keyword?/1`, `Mix.debug?/0`, `String.contains?/2`\n\nHowever, functions that return booleans and are valid in guards follow another convention, described next.\n\n## `is_` prefix (`is_foo`)\n\nType checks and other boolean checks that are allowed in guard clauses are named with an `is_` prefix.\n\nExamples: `Integer.is_even/1`, `is_list/1`\n\nThese 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. Type checks that are not valid in guard clauses do not follow this convention, such as `Keyword.keyword?/1`.\n\nA trailing question mark should not be used in combination with the `is_` prefix.\n\n## Special names\n\nSome names have specific meaning in Elixir. We detail those cases below.\n\n### length and size\n\nWhen you see `size` in a function name, it means the operation runs in constant time (also written as \"O(1) time\") because the size is stored alongside the data structure.\n\nExamples: `map_size/1`, `tuple_size/1`\n\nWhen you see `length`, the operation runs in linear time (\"O(n) time\") because the entire data structure has to be traversed.\n\nExamples: `length/1`, `String.length/1`\n\nIn other words, functions using the word \"size\" in its name will take the same amount of time whether the data structure is tiny or huge. Conversely, functions having \"length\" in its name will take more time as the data structure grows in size.\n\n### get, fetch, fetch!\n\nWhen you see the functions `get`, `fetch`, and `fetch!` for key-value data structures, you can expect the following behaviours:\n\n  * `get` returns a default value (which itself defaults to `nil`) if the key is not present, or returns the requested value.\n  * `fetch` returns `:error` if the key is not present, or returns `{:ok, value}` if it is.\n  * `fetch!` *raises* if the key is not present, or returns the requested value.\n\nExamples: `Map.get/2`, `Map.fetch/2`, `Map.fetch!/2`, `Keyword.get/2`, `Keyword.fetch/2`, `Keyword.fetch!/2`\n\n### compare\n\nThe function `compare/2` should return `:lt` if the first term is less than the second, `:eq` if the two\nterms compare as equivalent, or `:gt` if the first term is greater than the second.\n\nExamples: `DateTime.compare/2`\n\nNote that this specific convention is important due to the expectations of `Enum.sort/2`\n","isInternal":false,"tokens":1828,"sizeBytes":7517},{"name":"operators.md","path":"lib/elixir/pages/references/operators.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/operators.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Operators reference\n\nThis document is a complete reference of operators in Elixir, how they are parsed, how they can be defined, and how they can be overridden.\n\n## General operators\n\nElixir provides the following built-in operators:\n\n  * [`+`](`+/1`) and [`-`](`-/1`) - unary positive/negative\n  * [`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), and [`/`](`//2`) - basic arithmetic operations\n  * [`++`](`++/2`) and [`--`](`--/2`) - list concatenation and subtraction\n  * [`and`](`and/2`) and [`&&`](`&&/2`) - strict and relaxed boolean \"and\"\n  * [`or`](`or/2`) and [`||`](`||/2`) - strict and relaxed boolean \"or\"\n  * [`not`](`not/1`) and [`!`](`!/1`) - strict and relaxed boolean \"not\"\n  * [`in`](`in/2`) and [`not in`](`in/2`) - membership\n  * [`@`](`@/1`) - module attribute\n  * [`..`](`../0`), [`..`](`../2`), and [`..//`](`..///3`) - range creation\n  * [`<>`](`<>/2`) - binary concatenation\n  * [`|>`](`|>/2`) - pipeline\n  * [`=~`](`=~/2`) - text-based match\n\nMany of those can be used in guards. Consult the [list of allowed guard functions and operators](patterns-and-guards.md#list-of-allowed-functions-and-operators).\n\nAdditionally, there are a few other operators that Elixir parses but doesn't actually use.\nSee [Custom and overridden operators](#custom-and-overridden-operators) below for a list and for guidelines about their use.\n\nSome other operators are special forms and cannot be overridden:\n\n  * [`^`](`^/1`) - pin operator\n  * [`.`](`./2`) - dot operator\n  * [`=`](`=/2`) - match operator\n  * [`&`](`&/1`) - capture operator\n  * [`::`](`::/2`) - type operator\n\nFinally, these operators appear in the precedence table below but are only meaningful within certain constructs:\n\n  * `=>` - see [`%{}`](`%{}/1`)\n  * `when` - see [Guards](patterns-and-guards.md#guards)\n  * `<-` - see [`for`](`for/1`) and [`with`](`with/1`)\n  * `\\\\` - see [Default arguments](`Kernel#def/2-default-arguments`)\n\n## Comparison operators\n\nElixir provides the following built-in comparison operators (all of which can be used in guards):\n\n  * [`==`](`==/2`) - equal to\n  * [`===`](`===/2`) - strictly equal to\n  * [`!=`](`!=/2`) - not equal to\n  * [`!==`](`!==/2`) - strictly not equal to\n  * [`<`](`</2`) - less-than\n  * [`>`](`>/2`) - greater-than\n  * [`<=`](`<=/2`) - less-than or equal to\n  * [`>=`](`>=/2`) - greater-than or equal to\n\nThe only difference between [`==`](`==/2`) and [`===`](`===/2`) is that [`===`](`===/2`) is strict when it comes to comparing integers and floats:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 === 1.0\nfalse\n```\n\n[`!=`](`!=/2`) and [`!==`](`!==/2`) act as the negation of [`==`](`==/2`) and [`===`](`===/2`), respectively.\n\n## Operator precedence and associativity\n\nThe following is a list of all operators that Elixir is capable of parsing, ordered from higher to lower precedence, alongside their associativity:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`@`                                            | Unary\n`.`                                            | Left\n`+` `-` `!` `^` `not`                          | Unary\n`**`                                           | Left\n`*` `/`                                        | Left\n`+` `-`                                        | Left\n`++` `--` `+++` `---` `..` `<>`                | Right\n`//` (valid only inside `..//`)                | Right\n`in` `not in`                                  | Left\n`\\|>` `<<<` `>>>` `<<~` `~>>` `<~` `~>` `<~>`  | Left\n`<` `>` `<=` `>=`                              | Left\n`==` `!=` `=~` `===` `!==`                     | Left\n`&&` `&&&` `and`                               | Left\n`\\|\\|` `\\|\\|\\|` `or`                           | Left\n`=`                                            | Right\n`&`, `...`                                     | Unary\n`\\|`                                           | Right\n`::`                                           | Right\n`when`                                         | Right\n`<-` `\\\\`                                      | Left\n`=>` (valid only inside `%{}`)                 | None\n\nElixir also has two ternary operators:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`first..last//step`                            | Right\n`%{map \\| key => value, ...}`                  | None\n\n> #### Deprecated operator precedence {: .info}\n>\n> Elixir parses `not left in right` as `not(left in right)` and `!left in right` as `!(left in right)`, which mismatches the precedence table above, but such behaviour is deprecated and emits a warning. Both constructs must be written as `left not in right` instead. In future major versions, the parser will match the table above.\n\n## Custom and overridden operators\n\nElixir is capable of parsing a predefined set of operators. It's not possible to define new operators (as supported by some languages). However, not all operators that Elixir can parse are *used* by Elixir: for example, `+` and `||` are used by Elixir for addition and boolean *or*, but `<~>` is not used (but valid).\n\nTo define an operator, you can use the usual `def*` constructs (`def`, `defp`, `defmacro`, and so on) but with a syntax similar to how the operator is used:\n\n```elixir\ndefmodule MyOperators do\n  # We define ~> to return the maximum of the given two numbers,\n  # and <~ to return the minimum.\n\n  def a ~> b, do: max(a, b)\n  def a <~ b, do: min(a, b)\nend\n```\n\nTo use the newly defined operators, you **have to** import the module that defines them:\n\n```elixir\niex> import MyOperators\niex> 1 ~> 2\n2\niex> 1 <~ 2\n1\n```\n\nThe following is a table of all the operators that Elixir is capable of parsing, but that are not used by default:\n\n  * `|||`\n  * `&&&`\n  * `<<<`\n  * `>>>`\n  * `<<~`\n  * `~>>`\n  * `<~`\n  * `~>`\n  * `<~>`\n  * `+++`\n  * `---`\n  * `...`\n\nThe following operators are used by the `Bitwise` module when imported: [`&&&`](`Bitwise.&&&/2`), [`<<<`](`Bitwise.<<</2`), [`>>>`](`Bitwise.>>>/2`), and [`|||`](`Bitwise.|||/2`). See the `Bitwise` documentation for more information.\n\nNote that the Elixir community generally discourages custom operators. They can be hard to read and even more to understand, as they don't have a descriptive name like functions do. That said, some specific cases or custom domain specific languages (DSLs) may justify these practices.\n\nIt is also possible to replace predefined operators, such as `+`, but doing so is extremely discouraged.\n","isInternal":false,"tokens":1818,"sizeBytes":6637},{"name":"patterns-and-guards.md","path":"lib/elixir/pages/references/patterns-and-guards.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/patterns-and-guards.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Patterns and guards\n\nElixir provides pattern matching, which allows us to assert on the shape or extract values from data structures. Patterns are often augmented with guards, which give developers the ability to perform more complex checks, albeit limited.\n\nThis document provides a complete reference on patterns and guards, their semantics, where they are allowed, and how to extend them.\n\n## Patterns\n\nPatterns in Elixir are made of variables, literals, and data structure specific syntax. One of the most used constructs to perform pattern matching is the match operator ([`=`](`=/2`)):\n\n```iex\niex> x = 1\n1\niex> 1 = x\n1\n```\n\nIn the example above, `x` starts without a value and has `1` assigned to it. Then, we compare the value of `x` to the literal `1`, which succeeds as they are both `1`.\n\nMatching `x` against 2 would raise:\n\n```iex\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nPatterns are not bidirectional. If you have a variable `y` that was never assigned to (often called an unbound variable) and you write `1 = y`, an error will be raised:\n\n```iex\niex> 1 = y\n** (CompileError) iex:2: undefined variable \"y\"\n```\n\nIn other words, patterns are allowed only on the left side of `=`. The right side of `=` follows the regular evaluation semantics of the language.\n\nNow let's cover the pattern matching rules for each construct and then for each relevant data types.\n\n### Variables\n\nVariables in patterns are always assigned to:\n\n```iex\niex> x = 1\n1\niex> x = 2\n2\niex> x\n2\n```\n\nIn other words, Elixir supports rebinding. In case you don't want the value of a variable to change, you can use the pin operator (`^`):\n\n```iex\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nIf the same variable appears multiple times in the same pattern, then all of them must be bound to the same value:\n\n```iex\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nHowever, a variable cannot be defined through itself in the same pattern. This includes cases where the variable appears on both sides of a nested match operator:\n\n```elixir\n{:ok, x} = {x, :ok}\n%{a: value} = %{b: value}\n```\n\nSuch patterns are rejected as cyclic variable definitions. You can rewrite them by matching once and then using guards or separate comparisons for the additional constraints.\n\nThe underscore variable (`_`) has a special meaning as it can never be bound to any value. It is especially useful when you don't care about certain value in a pattern:\n\n```iex\niex> {_, integer} = {:not_important, 1}\n{:not_important, 1}\niex> integer\n1\niex> _\n** (CompileError) iex:3: invalid use of _\n```\n\nA pinned value represents the value itself and not its – even if syntactically equal – pattern. The right hand side is compared to be equal to the pinned value:\n\n```iex\niex> x = %{}\n%{}\niex> {:ok, %{}} = {:ok, %{a: 13}}\n{:ok, %{a: 13}}\niex> {:ok, ^x} = {:ok, %{a: 13}}\n** (MatchError) no match of right hand side value: {:ok, %{a: 13}}\n    (stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6\n    iex:2: (file)\n```\n\n### Literals (numbers and atoms)\n\nAtoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:\n\n```iex\niex> :atom = :atom\n:atom\niex> :atom = :another_atom\n** (MatchError) no match of right hand side value: :another_atom\n```\n\nSimilar rule applies to numbers. Finally, note that numbers in patterns perform strict comparison. In other words, integers to do not match floats:\n\n```iex\niex> 1 = 1.0\n** (MatchError) no match of right hand side value: 1.0\n```\n\n### Tuples\n\nTuples may appear in patterns using the curly brackets syntax (`{}`). A tuple in a pattern will match only tuples of the same size, where each individual tuple element must also match:\n\n```iex\niex> {:ok, integer} = {:ok, 13}\n{:ok, 13}\n\n# won't match due to different size\niex> {:ok, integer} = {:ok, 11, 13}\n** (MatchError) no match of right hand side value: {:ok, 11, 13}\n\n# won't match due to mismatch on first element\niex> {:ok, binary} = {:error, :enoent}\n** (MatchError) no match of right hand side value: {:error, :enoent}\n```\n\n### Lists\n\nLists may appear in patterns using the square brackets syntax (`[]`). A list in a pattern will match only lists of the same size, where each individual list element must also match:\n\n```iex\niex> [:ok, integer] = [:ok, 13]\n[:ok, 13]\n\n# won't match due to different size\niex> [:ok, integer] = [:ok, 11, 13]\n** (MatchError) no match of right hand side value: [:ok, 11, 13]\n\n# won't match due to mismatch on first element\niex> [:ok, binary] = [:error, :enoent]\n** (MatchError) no match of right hand side value: [:error, :enoent]\n```\n\nOpposite to tuples, lists also allow matching on non-empty lists by using the `[head | tail]` notation, which matches on the `head` and `tail` of a list:\n\n```iex\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nMultiple elements may prefix the `| tail` construct:\n\n```iex\niex> [first, second | tail] = [1, 2, 3]\n[1, 2, 3]\niex> tail\n[3]\n```\n\nNote `[head | tail]` does not match empty lists:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nGiven charlists are represented as a list of integers, one can also perform prefix matches on charlists using the list concatenation operator ([`++`](`++/2`)):\n\n```elixir\niex> ~c\"hello \" ++ world = ~c\"hello world\"\n~c\"hello world\"\niex> world\n~c\"world\"\n```\n\nWhich is equivalent to matching on `[?h, ?e, ?l, ?l, ?o, ?\\s | world]`. Suffix matches (`hello ++ ~c\" world\"`) are not valid patterns.\n\n### Maps\n\nMaps may appear in patterns using the percentage sign followed by the curly brackets syntax (`%{}`). Opposite to lists and tuples, maps perform a subset match. This means a map pattern will match any other map that has at least all of the keys in the pattern.\n\nHere is an example where all keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\"}\n%{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nHere is when a subset of the keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\", age: 23}\n%{age: 23, name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf a key in the pattern is not available in the map, then they won't match:\n\n```iex\niex> %{name: name, age: age} = %{name: \"meg\"}\n** (MatchError) no match of right hand side value: %{name: \"meg\"}\n```\n\nNote that the empty map will match all maps, which is a contrast to tuples and lists, where an empty tuple or an empty list will only match empty tuples and empty lists respectively:\n\n```iex\niex> %{} = %{name: \"meg\"}\n%{name: \"meg\"}\n```\n\nFinally, note map keys in patterns must always be literals or previously bound variables matched with the pin operator.\n\n### Structs\n\nStructs may appear in patterns using the percentage sign, the struct module name or a variable followed by the curly brackets syntax (`%{}`).\n\nGiven the following struct:\n\n```elixir\ndefmodule User do\n  defstruct [:name]\nend\n```\n\nHere is an example where all keys match:\n\n```iex\niex> %User{name: name} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf an unknown key is given, the compiler will raise an error:\n\n```iex\niex> %User{type: type} = %User{name: \"meg\"}\n** (CompileError) iex: unknown key :type for struct User\n```\n\nThe struct name can be extracted when putting a variable instead of a module name:\n\n```elixir\niex> %struct_name{} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> struct_name\nUser\n```\n\n### Binaries\n\nBinaries may appear in patterns using the double less-than/greater-than syntax ([`<<>>`](`<<>>/1`)). A binary in a pattern can match multiple segments at the same time, each with different type, size, and unit:\n\n```iex\niex> <<val::unit(8)-size(2)-integer>> = <<123, 56>>\n\"{8\"\niex> val\n31544\n```\n\nSee the documentation for [`<<>>`](`<<>>/1`) for a complete definition of pattern matching for binaries.\n\nFinally, remember that strings in Elixir are UTF-8 encoded binaries. This means that, similar to charlists, prefix matches on strings are also possible with the binary concatenation operator ([`<>`](`<>/2`)):\n\n```elixir\niex> \"hello \" <> world = \"hello world\"\n\"hello world\"\niex> world\n\"world\"\n```\n\nSuffix matches (`hello <> \" world\"`) are not valid patterns.\n\n## Guards\n\nGuards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed, such as function definitions, case clauses, and others.\n\nNot all expressions are allowed in guard clauses, but only a handful of them. This is a deliberate choice. This way, Elixir (through Erlang) ensures that all guards are predictable (no mutations or other side-effects) and they can be optimized and performed efficiently.\n\n### List of allowed functions and operators\n\nYou can find the built-in list of guards [in the `Kernel` module](`Kernel#guards`). Here is an overview:\n\n  * comparison operators ([`==`](`==/2`), [`!=`](`!=/2`), [`===`](`===/2`), [`!==`](`!==/2`),\n    [`<`](`</2`), [`<=`](`<=/2`), [`>`](`>/2`), [`>=`](`>=/2`)), [`max`](`max/2`), [`min`](`min/2`)\n  * strictly boolean operators ([`and`](`and/2`), [`or`](`or/2`), [`not`](`not/1`)). Note [`&&`](`&&/2`), [`||`](`||/2`), and [`!`](`!/1`) sibling operators are **not allowed** as they're not *strictly* boolean - meaning they don't require arguments to be booleans\n  * arithmetic unary operators ([`+`](`+/1`), [`-`](`-/1`))\n  * arithmetic binary operators ([`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), [`/`](`//2`))\n  * [`in`](`in/2`) and [`not in`](`in/2`) operators (as long as the right-hand side is a list or a range)\n  * \"type-check\" functions (`is_list/1`, `is_number/1`, and the like)\n  * functions that work on built-in data types (`abs/1`, `hd/1`, `map_size/1`, and others)\n  * the `map.field` syntax\n\nThe module `Bitwise` also includes a handful of [Erlang bitwise operations as guards](Bitwise.html#guards).\n\nMacros constructed out of any combination of the above guards are also valid guards - for example, `Integer.is_even/1`. For more information, see the \"Custom patterns and guards expressions\" section shown below.\n\n### Why guards\n\nLet's see an example of a guard used in a function clause:\n\n```elixir\ndef empty_map?(map) when map_size(map) == 0, do: true\ndef empty_map?(map) when is_map(map), do: false\n```\n\nGuards start with the `when` operator, followed by a guard expression. The clause will be executed if and only if the guard expression returns `true`. Multiple boolean conditions can be combined with the [`and`](`and/2`) and [`or`](`or/2`) operators.\n\nWriting the `empty_map?/1` function by only using pattern matching would not be possible (as pattern matching on `%{}` would match *any* map, not only the empty ones).\n\n### Non-passing guards\n\nA function clause will be executed if and only if its guard expression evaluates to `true`. If any other value is returned, the function clause will be skipped. In particular, guards have no concept of \"truthy\" or \"falsy\".\n\nFor example, imagine a function that checks that the head of a list is not `nil`:\n\n```elixir\ndef not_nil_head?([head | _]) when head, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> false\n```\n\nEven though the head of the list is not `nil`, the first clause for `not_nil_head?/1` fails because the expression does not evaluate to `true`, but to `\"some_value\"`, therefore triggering the second clause which returns `false`. To make the guard behave correctly, you must ensure that the guard evaluates to `true`, like so:\n\n```elixir\ndef not_nil_head?([head | _]) when head != nil, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> true\n```\n\n### Errors in guards\n\nIn guards, when functions would normally raise exceptions, they cause the guard to fail instead.\n\nFor example, the `tuple_size/1` function only works with tuples. If we use it with anything else, an argument error is raised:\n\n```elixir\niex> tuple_size(\"hello\")\n** (ArgumentError) argument error\n```\n\nHowever, when used in guards, the corresponding clause will fail to match instead of raising an error:\n\n```elixir\niex> case \"hello\" do\n...>   something when tuple_size(something) == 2 ->\n...>     :worked\n...>   _anything_else ->\n...>     :failed\n...> end\n:failed\n```\n\nIn many cases, we can take advantage of this. In the code above, we used `tuple_size/1` to both check that the given value is a tuple *and* check its size (instead of using `is_tuple(something) and tuple_size(something) == 2`).\n\nHowever, if your guard has multiple conditions, such as checking for tuples or maps, it is best to call type-check functions like `is_tuple/1` before `tuple_size/1`, otherwise the whole guard will fail if a tuple is not given. Alternatively, your function clause can use multiple guards as shown in the following section.\n\n### Multiple guards in the same clause\n\nThere exists an additional way to simplify a chain of `or` expressions in guards: Elixir supports writing \"multiple guards\" in the same clause. The following code:\n\n```elixir\ndef categorize_number(term) when is_integer(term) or is_float(term) or is_nil(term),\n  do: :maybe_number\ndef categorize_number(_other),\n  do: :something_else\n```\n\ncan be alternatively written as:\n\n```elixir\ndef categorize_number(term)\n    when is_integer(term)\n    when is_float(term)\n    when is_nil(term) do\n  :maybe_number\nend\n\ndef categorize_number(_other) do\n  :something_else\nend\n```\n\nIf each guard expression always returns a boolean, the two forms are equivalent. However, recall that if any function call in a guard raises an exception, the entire guard fails. To illustrate this, the following function will not detect empty tuples:\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and tuple_size/1 will not be evaluated\n  def empty?(val) when map_size(val) == 0 or tuple_size(val) == 0, do: true\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> false # true was expected!\n```\n\nThis could be corrected by ensuring that no exception is raised, either via type checks like `is_map(val) and map_size(val) == 0`, or by using multiple guards, so that if an exception causes one guard to fail, the next one is evaluated.\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and the second guard will be evaluated\n  def empty?(val)\n      when map_size(val) == 0\n      when tuple_size(val) == 0,\n      do: true\n\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> true\n```\n\n## Where patterns and guards can be used\n\nIn the examples above, we have used the match operator ([`=`](`=/2`)) and function clauses to showcase patterns and guards respectively. Here is the list of the built-in constructs in Elixir that support patterns and guards.\n\n  * `match?/2`:\n\n    ```elixir\n    match?({:ok, value} when value > 0, {:ok, 13})\n    ```\n\n  * function clauses:\n\n    ```elixir\n    def type(term) when is_integer(term), do: :integer\n    def type(term) when is_float(term), do: :float\n    ```\n\n  * [`case`](`case/2`) expressions:\n\n    ```elixir\n    case x do\n      1 -> :one\n      2 -> :two\n      n when is_integer(n) and n > 2 -> :larger_than_two\n    end\n    ```\n\n  * anonymous functions (`fn/1`):\n\n    ```elixir\n    larger_than_two? = fn\n      n when is_integer(n) and n > 2 -> true\n      n when is_integer(n) -> false\n    end\n    ```\n\n  * [`for`](`for/1`) and [`with`](`with/1`) support patterns and guards on the left side of `<-`:\n\n    ```elixir\n    for x when x >= 0 <- [1, -2, 3, -4], do: x\n    ```\n\n    `with` also supports the `else` keyword, which supports patterns matching and guards.\n\n  * [`try`](`try/1`) supports patterns and guards on `catch` and `else`\n\n  * [`receive`](`receive/1`) supports patterns and guards to match on the received messages.\n\n  * custom guards can also be defined with `defguard/1` and `defguardp/1`. A custom guard can only be defined based on existing guards.\n\nNote that the match operator ([`=`](`=/2`)) does *not* support guards:\n\n```elixir\n{:ok, binary} = File.read(\"some/file\")\n```\n\n## Custom patterns and guards expressions\n\nOnly the constructs listed in this page are allowed in patterns and guards. However, we can take advantage of macros to write custom patterns 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 boils down to a combination of the constructs above.\n\nFor example, the `Record` module in Elixir provides a series of macros to be used in patterns and guards that allows tuples to have named fields during compilation.\n\nFor defining your own guards, Elixir even provides conveniences in `defguard` and `defguardp`. Let's look at a quick case study: we want to check whether an argument is an even or an odd integer. With pattern matching this is impossible because there is an infinite number of integers, and therefore we can't pattern match on every single one of them. Therefore we must use guards. We will just focus on checking for even numbers since checking for the odd ones is almost identical.\n\nSuch a guard would look like this:\n\n```elixir\ndef my_function(number) when is_integer(number) and rem(number, 2) == 0 do\n  # do stuff\nend\n```\n\nIt would be repetitive to write every time we need this check. Instead, you can use `defguard/1` and `defguardp/1` to create guard macros. Here's an example how:\n\n```elixir\ndefmodule MyInteger do\n  defguard is_even(term) when is_integer(term) and rem(term, 2) == 0\nend\n```\n\nand then:\n\n```elixir\nimport MyInteger, only: [is_even: 1]\n\ndef my_function(number) when is_even(number) do\n  # do stuff\nend\n```\n\nWhile it's possible to create custom guards with macros, it's recommended to define them using `defguard/1` and `defguardp/1` which perform additional compile-time checks.\n","isInternal":false,"tokens":4972,"sizeBytes":17999},{"name":"sbom.md","path":"lib/elixir/pages/references/sbom.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/sbom.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Software Bill of Materials\n\nA Software Bill of Materials (SBoM) is a structured inventory of the components that make up a software system. This guide explains what SBoMs are, why they matter, and how to generate them for Elixir projects.\n\n## What is an SBoM?\n\nAn SBoM is a formal, machine-readable record of all components in a piece of software. Think of it as a detailed ingredient list for your application. A typical SBoM includes:\n\n  * **Dependencies**: all libraries and packages your project uses\n  * **Versions**: the exact version of each component\n  * **Source locations**: where each component was obtained (Hex, GitHub, etc.)\n  * **Checksums**: cryptographic hashes to verify integrity\n  * **Licensing information**: the license under which each component is distributed\n\nTwo widely adopted standards exist for SBoM formats:\n\n  * [CycloneDX](https://cyclonedx.org/): a lightweight standard designed for security contexts\n  * [SPDX](https://spdx.dev/): a more comprehensive standard originally focused on licensing\n\nBoth formats are machine-readable (JSON, XML) and designed to be consumed by automated tooling.\n\n> #### SBoM is an inventory, not a certification {: .info}\n>\n> An SBoM does not claim that software is secure, compliant, or free of vulnerabilities.\n> It simply provides a detailed inventory that enables further analysis. Security and\n> compliance assessments are performed by separate tools that consume the SBoM.\n\n## Why generate SBoMs?\n\nThere are three main reasons to generate SBoMs for your projects.\n\n### Vulnerability analysis\n\nWhen a security vulnerability (CVE) is discovered in a library, you need to quickly determine if your projects are affected. SBoMs make this possible by providing a complete inventory of your dependencies.\n\nTools like [OWASP Dependency-Track](https://dependencytrack.org/) continuously monitor your SBoMs against vulnerability databases. When a new CVE is published, you get notified if any of your projects use the affected component.\n\nWithout an SBoM, answering \"are we affected by CVE-2024-XXXXX?\" means manually checking each project, which is time-consuming and error-prone.\n\n### Regulatory requirements\n\nSBoMs are required by some regulations and procurement policies:\n\n  * **US Executive Order 14028** (2021) requires SBoMs for certain software supplied to the U.S. federal government, particularly for designated critical software\n  * **EU Cyber Resilience Act** introduces requirements for component inventories (commonly fulfilled using SBoMs) for products with digital elements placed on the EU market\n  * **Safety-critical industries** (medical devices, automotive, aerospace) often require detailed component inventories as part of certification\n\nCustomers and partners may also request SBoMs as part of their own compliance efforts.\n\n### License compliance\n\nEvery dependency in your project comes with a license. An SBoM provides a starting point for license review by listing the declared license for each package. This helps you:\n\n  * Get an overview of licenses in your dependency tree\n  * Flag packages that may need closer review\n  * Support due diligence for acquisitions, audits, or legal review\n\nNote that package-level license information (as provided by mix_sbom) reflects what the package declares, not necessarily all licenses present in its source files. For thorough license compliance, file-level scanning tools like ORT provide deeper analysis.\n\n## Generating SBoMs with mix_sbom\n\n[mix_sbom](https://github.com/erlef/mix_sbom) is an EEF project that generates CycloneDX SBoMs for Elixir projects.\n\n### Installation\n\nThere are several ways to install mix_sbom:\n\n  * **As a project dependency**: add `sbom` to your `mix.exs`\n  * **As a global escript**: run `mix escript.install hex sbom` (requires Elixir 1.19.4+)\n  * **As a standalone binary**: download from the [releases page](https://github.com/erlef/mix_sbom/releases)\n\nThe standalone binary is useful for CI environments or when you don't want to modify your project's dependencies. It requires no local Elixir or Erlang installation.\n\n### Basic usage\n\nTo generate an SBoM for your project using the standalone binary:\n\n```console\n$ mix_sbom cyclonedx /path/to/your/project\n```\n\nThis creates a `bom.cdx.json` file in CycloneDX format containing your project's complete dependency tree.\n\n### Common options\n\nThe most useful options are:\n\n  * `-o, --output PATH`: specify the output file (default: `bom.cdx.json`)\n  * `-t, --format FORMAT`: output format (`json`, `xml`, or `protobuf`)\n  * `-s, --schema VERSION`: CycloneDX schema version\n\nFor example, to generate an XML format SBoM:\n\n```console\n$ mix_sbom cyclonedx --format xml --output sbom.xml /path/to/project\n```\n\n## CI integration\n\nFor automated SBoM generation, mix_sbom provides a GitHub Action:\n\n```yaml\nname: Generate SBoM\non:\n  release:\n    types: [published]\n\njobs:\n  sbom:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: erlef/mix_sbom@v0\n        with:\n          path: \".\"\n          format: \"json\"\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sbom\n          path: bom.cdx.json\n```\n\nThis workflow generates an SBoM whenever you publish a release and uploads it as a build artifact. See the [action's documentation](https://github.com/erlef/mix_sbom) for additional options.\n\n## Deeper analysis with ORT\n\nmix_sbom provides package-level license information based on what each dependency declares. However, some compliance workflows require file-level scanning. A package might declare an MIT license but contain individual files under different licenses, or include vendored code with its own licensing terms.\n\nThe [OSS Review Toolkit (ORT)](https://oss-review-toolkit.org/) addresses this by scanning actual source files for license headers and copyright notices. ORT supports Mix projects and provides:\n\n  * **File-level license detection**: scans source code for license texts and SPDX identifiers\n  * **Copyright holder identification**: extracts copyright notices from files\n  * **Policy enforcement**: define rules for allowed and denied licenses\n  * **Multi-ecosystem support**: analyze projects that span multiple package managers\n\nFor organizations with strict compliance requirements, ORT complements mix_sbom by providing the deeper analysis needed for thorough license audits.\n\nSee the [ORT Mix plugin documentation](https://oss-review-toolkit.org/ort/docs/plugins/package-managers/Mix) for details.\n\n## Next steps\n\n  * [CycloneDX Specification](https://cyclonedx.org/specification/overview/): learn more about the SBoM format\n  * [OWASP Dependency-Track](https://dependencytrack.org/): continuous SBoM analysis platform\n  * [mix_sbom documentation](https://sbom.hexdocs.pm): full documentation and advanced options\n","isInternal":false,"tokens":1541,"sizeBytes":6896},{"name":"syntax-reference.md","path":"lib/elixir/pages/references/syntax-reference.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/syntax-reference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Syntax reference\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). This means the Elixir syntax is mostly uniform with a handful of \"syntax sugar\" constructs to reduce the noise in common Elixir idioms.\n\nThis document covers all of Elixir syntax constructs as a reference and then discuss their exact AST representation.\n\n## Reserved words\n\nThese are the reserved words in the Elixir language. They are detailed throughout this guide but summed up here for convenience:\n\n  * `true`, `false`, `nil` - used as atoms\n  * `when`, `and`, `or`, `not`, `in` - used as operators\n  * `fn` - used for anonymous function definitions\n  * `do`, `end`, `catch`, `rescue`, `after`, `else` - used in do-end blocks\n\n## Data types\n\n### Numbers\n\nIntegers (`1234`) and floats (`123.4`) in Elixir are represented as a sequence of digits that may be separated by underscore for readability purposes, such as `1_000_000`. Integers never contain a dot (`.`) in their representation. Floats contain a dot and at least one other digit after the dot. Floats also support the scientific notation, such as `123.4e10` or `123.4E10`.\n\n### Atoms\n\nUnquoted atoms start with a colon (`:`) which must be immediately followed by a Unicode letter or an underscore. The atom may continue using a sequence of Unicode letters, numbers, underscores, and `@`. Atoms may end in `!` or `?`. Valid unquoted atoms are: `:ok`, `:ISO8601`, and `:integer?`.\n\nIf the colon is immediately followed by a pair of double- or single-quotes surrounding the atom name, the atom is considered quoted. In contrast with an unquoted atom, this one can be made of any Unicode character (not only letters), such as `:'🌢 Elixir'`, `:\"++olá++\"`, and `:\"123\"`.\n\nQuoted and unquoted atoms with the same name are considered equivalent, so `:atom`, `:\"atom\"`, and `:'atom'` represent the same atom. The only catch is that the compiler will warn when quotes are used in atoms that do not need to be quoted.\n\nAll operators in Elixir are also valid atoms. Valid examples are `:foo`, `:FOO`, `:foo_42`, `:foo@bar`, and `:++`. Invalid examples are `:@foo` (`@` is not allowed at start), `:123` (numbers are not allowed at start), and `:(*)` (not a valid operator).\n\n`true`, `false`, and `nil` are reserved words that are represented by the atoms `:true`, `:false` and `:nil` respectively.\n\nTo learn more about all Unicode characters allowed in atom, see the [Unicode syntax](unicode-syntax.md) document.\n\n### Strings\n\nSingle-line strings in Elixir are written between double-quotes, such as `\"foo\"`. Any double-quote inside the string must be escaped with `\\ `. Strings support Unicode characters and are stored as UTF-8 encoded binaries.\n\nMulti-line strings in Elixir are called heredocs. They are written with three double-quotes, and can have unescaped quotes within them. The resulting string will end with a newline. The indentation of the last `\"\"\"` is used to strip indentation from the inner string. For example:\n\n```elixir\niex> test = \"\"\"\n...>     this\n...>     is\n...>     a\n...>     test\n...> \"\"\"\n\"    this\\n    is\\n    a\\n    test\\n\"\niex> test = \"\"\"\n...>     This\n...>     Is\n...>     A\n...>     Test\n...>     \"\"\"\n\"This\\nIs\\nA\\nTest\\n\"\n```\n\nStrings are always represented as themselves in the AST.\n\n### Charlists\n\nCharlists are lists of non-negative integers where each integer represents a Unicode code point.\n\n```elixir\niex(6)> 'abc' === [97, 98, 99]\ntrue\n```\n\nCharlists are written in single-quotes, such as `'foo'`. Any single-quote inside the string must be escaped with `\\ `.\nMulti-line charlists are written with three single-quotes (`'''`), the same way multi-line strings are.\nHowever, this syntax is deprecated in favor of the charlist sigil `~c`.\n\nCharlists are always represented as themselves in the AST.\n\nFor more in-depth information, please read the \"Charlists\" section in the `List` module.\n\n### Lists, tuples and binaries\n\nData structures such as lists, tuples, and binaries are marked respectively by the delimiters `[...]`, `{...}`, and `<<...>>`. Each element is separated by comma. A trailing comma is also allowed, such as in `[1, 2, 3,]`.\n\n### Maps and keyword lists\n\nMaps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{\"hello\" => 1, 2 => \"world\"}`.\n\nBoth keyword lists (list of two-element tuples where the first element is an atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: \"world\"}` is equivalent to `%{:hello => \"world\"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.\n\n### Structs\n\nStructs built on the map syntax by passing the struct name between `%` and `{`. For example, `%User{...}`.\n\n## Expressions\n\n### Variables\n\nVariables in Elixir must start with an underscore or a Unicode letter that is not in uppercase or titlecase. The variable may continue using a sequence of Unicode letters, numbers, and underscores. Variables may end in `?` or `!`. To learn more about all Unicode characters allowed in variables, see the [Unicode syntax](unicode-syntax.md) document.\n\n[Elixir's naming conventions](naming-conventions.md) recommend variables to be in `snake_case` format.\n\n### Non-qualified calls (local calls)\n\nNon-qualified calls, such as `add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments.\n\nParentheses are required for zero-arity calls (i.e. calls without arguments), to avoid ambiguity with variables. If parentheses are used, they must immediately follow the function name *without spaces*. For example, `add (1, 2)` is a syntax error, since `(1, 2)` is treated as an invalid block which is attempted to be given as a single argument to `add`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Operators\n\nAs many programming languages, Elixir also support operators as non-qualified calls with their precedence and associativity rules. Constructs such as `=`, `when`, `&` and `@` are simply treated as operators. See [the Operators page](operators.md) for a full reference.\n\n### Qualified calls (remote calls)\n\nQualified calls, such as `Math.add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments. Qualified calls also support operators, such as `Kernel.+(1, 2)`. Elixir also allows the function name to be written between double- or single-quotes, allowing any character in between the quotes, such as `Math.\"++add++\"(1, 2)`.\n\nSimilar to non-qualified calls, parentheses have different meaning for zero-arity calls (i.e. calls without arguments). If parentheses are used, such as `mod.fun()`, it means a function call. If parenthesis are skipped, such as `map.field`, it means accessing a field of a map.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Aliases\n\nAliases are constructs that expand to atoms at compile-time. The alias `String` expands to the atom `:\"Elixir.String\"`. Aliases must start with an ASCII uppercase character which may be followed by any ASCII letter, number, or underscore. Non-ASCII characters are not supported in aliases.\n\nMultiple aliases can be joined with `.`, such as `MyApp.String`, and it expands to the atom `:\"Elixir.MyApp.String\"`. The dot is effectively part of the name but it can also be used for composition. If you define `alias MyApp.Example, as: Example` in your code, then `Example` will always expand to `:\"Elixir.MyApp.Example\"` and `Example.String` will expand to `:\"Elixir.MyApp.Example.String\"`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend aliases to be in `CamelCase` format.\n\n### Module attributes\n\nModule attributes are module-specific storage and are written as the composition of the unary operator `@` with variables and local calls. For example, to write to a module attribute named `foo`, use `@foo \"value\"`, and use `@foo` to read from it. Given module attributes are written using existing constructs, they follow the same rules above defined for operators, variables, and local calls.\n\n### Blocks\n\nBlocks are multiple Elixir expressions separated by newlines or semi-colons. A new block may be created at any moment by using parentheses.\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is used to establish a relationship between left and right, commonly referred as clauses. The left side may have zero, one, or more arguments; the right side is zero, one, or more expressions separated by new line. The `->` may appear one or more times between one of the following terminators: `do`-`end`, `fn`-`end` or `(`-`)`. When `->` is used, only other clauses are allowed between those terminators. Mixing clauses and regular expressions is invalid syntax.\n\nIt is seen on `case` and `cond` constructs between `do` and `end`:\n\n```elixir\ncase 1 do\n  2 -> 3\n  4 -> 5\nend\n\ncond do\n  true -> false\nend\n```\n\nSeen in typespecs between `(` and `)`:\n\n```elixir\n(integer(), boolean() -> integer())\n```\n\nIt is also used between `fn` and `end` for building anonymous functions:\n\n```elixir\nfn\n  x, y -> x + y\nend\n```\n\n### Sigils\n\nSigils start with `~` and are followed by one lowercase letter or by one or more uppercase letters, immediately followed by one of the following pairs:\n\n  * `(` and `)`\n  * `{` and `}`\n  * `[` and `]`\n  * `<` and `>`\n  * `\"` and `\"`\n  * `'` and `'`\n  * `|` and `|`\n  * `/` and `/`\n\nAfter closing the pair, zero or more ASCII letters and digits can be given as a modifier. Sigils are expressed as non-qualified calls prefixed with `sigil_` where the first argument is the sigil contents as a string and the second argument is a list of integers as modifiers:\n\nIf the sigil letter is in uppercase, no interpolation is allowed in the sigil, otherwise its contents may be dynamic. Compare the results of the sigils below for more information:\n\n```elixir\n~s/f#{\"o\"}o/\n~S/f#{\"o\"}o/\n```\n\nSigils are useful to encode text with their own escaping rules, such as regular expressions, datetimes, and others.\n\n## The Elixir AST\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). Elixir's AST is a regular Elixir data structure composed of the following elements:\n\n  * atoms - such as `:foo`\n  * integers - such as `42`\n  * floats - such as `13.1`\n  * strings - such as `\"hello\"`\n  * lists - such as `[1, 2, 3]`\n  * tuples with two elements - such as `{\"hello\", :world}`\n  * tuples with three elements, representing calls or variables, as explained next\n\nThe building block of Elixir's AST is a call, such as:\n\n```elixir\nsum(1, 2, 3)\n```\n\nwhich is represented as a tuple with three elements:\n\n```elixir\n{:sum, meta, [1, 2, 3]}\n```\n\nthe first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.\n\nWe can retrieve the AST for any Elixir expression by calling `quote`:\n\n```elixir\nquote do\n  sum()\nend\n#=> {:sum, [], []}\n```\n\nVariables are also represented using a tuple with three elements and a combination of lists and atoms, for example:\n\n```elixir\nquote do\n  sum\nend\n#=> {:sum, [], Elixir}\n```\n\nYou can see that variables are also represented with a tuple, except the third element is an atom expressing the variable context.\n\nOver the course of this section, we will explore many Elixir syntax constructs alongside their AST representations.\n\n### Operators\n\nOperators are treated as non-qualified calls:\n\n```elixir\nquote do\n  1 + 2\nend\n#=> {:+, [], [1, 2]}\n```\n\nNote that `.` is also an operator. Remote calls use the dot in the AST with two arguments, where the second argument is always an atom:\n\n```elixir\nquote do\n  foo.bar(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}\n```\n\nCalling anonymous functions uses the dot in the AST with a single argument, mirroring the fact the function name is \"missing\" from right side of the dot:\n\n```elixir\nquote do\n  foo.(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}\n```\n\n### Aliases\n\nAliases are represented by an `__aliases__` call with each segment separated by a dot as an argument:\n\n```elixir\nquote do\n  Foo.Bar.Baz\nend\n#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}\n\nquote do\n  __MODULE__.Bar.Baz\nend\n#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}\n```\n\nAll arguments, except the first, are guaranteed to be atoms.\n\n### Data structures\n\nRemember that lists are literals, so they are represented as themselves in the AST:\n\n```elixir\nquote do\n  [1, 2, 3]\nend\n#=> [1, 2, 3]\n```\n\nTuples have their own representation, except for two-element tuples, which are represented as themselves:\n\n```elixir\nquote do\n  {1, 2}\nend\n#=> {1, 2}\n\nquote do\n  {1, 2, 3}\nend\n#=> {:{}, [], [1, 2, 3]}\n```\n\nBinaries have a representation similar to tuples, except they are tagged with `:<<>>` instead of `:{}`:\n\n```elixir\nquote do\n  <<1, 2, 3>>\nend\n#=> {:<<>>, [], [1, 2, 3]}\n```\n\nThe same applies to maps, where pairs are treated as a list of tuples with two elements:\n\n```elixir\nquote do\n  %{1 => 2, 3 => 4}\nend\n#=> {:%{}, [], [{1, 2}, {3, 4}]}\n```\n\n### Blocks\n\nBlocks are represented as a `__block__` call with each line as a separate argument:\n\n```elixir\nquote do\n  1\n  2\n  3\nend\n#=> {:__block__, [], [1, 2, 3]}\n\nquote do 1; 2; 3; end\n#=> {:__block__, [], [1, 2, 3]}\n```\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is represented similar to operators except that they are always part of a list, its left side represents a list of arguments and the right side is an expression.\n\nFor example, in `case` and `cond`:\n\n```elixir\nquote do\n  case 1 do\n    2 -> 3\n    4 -> 5\n  end\nend\n#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}\n\nquote do\n  cond do\n    true -> false\n  end\nend\n#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}\n```\n\nBetween `(` and `)`:\n\n```elixir\nquote do\n  (1, 2 -> 3\n   4, 5 -> 6)\nend\n#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]\n```\n\nBetween `fn` and `end`:\n\n```elixir\nquote do\n  fn\n    1, 2 -> 3\n    4, 5 -> 6\n  end\nend\n#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}\n```\n\n### Qualified tuples\n\nQualified tuples (`foo.{bar, baz}`) are represented by a `{:., [], [expr, :{}]}` call, where the `expr` represents the left hand side of the dot, and the arguments represent the elements inside the curly braces. This is used in Elixir to provide multi aliases:\n\n```elixir\nquote do\n  Foo.{Bar, Baz}\nend\n#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}\n```\n\n### `do`-`end` blocks\n\nElixir's `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:\n\n```elixir\nif true do\n  this\nelse\n  that\nend\n```\n\nis the same as:\n\n```elixir\nif(true, do: (this), else: (that))\n```\n\nWhile the construct above does not require custom nodes in Elixir's AST, they are restricted only to certain keywords, listed next:\n\n  * `after`\n  * `catch`\n  * `else`\n  * `rescue`\n\nYou will find them in constructs such as `receive`, `try`, and others. You can also find more examples in [the Optional Syntax chapter](../getting-started/optional-syntax.md).\n","isInternal":false,"tokens":4158,"sizeBytes":15535},{"name":"typespecs.md","path":"lib/elixir/pages/references/typespecs.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/typespecs.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Typespecs reference\n\n> #### Typespecs are not set-theoretic types {: .warning}\n>\n> Elixir is in the process of implementing its\n> [own type system](./gradual-set-theoretic-types.md) based on set-theoretic types.\n> Typespecs, which are described in the following document, are a distinct notation\n> for declaring types and specifications based on Erlang.\n> Typespecs may be phased out as the set-theoretic type effort moves forward.\n\nElixir is a dynamically typed language, and as such, type specifications are never used by the compiler to optimize or modify code. Still, using type specifications is useful because:\n\n  * they provide documentation (for example, tools such as [`ExDoc`](https://ex-doc.hexdocs.pm/) show type specifications in the documentation)\n  * they're used by tools such as [Dialyzer](`:dialyzer`), that can analyze code with typespecs to find type inconsistencies and possible bugs\n\nType specifications (most often referred to as *typespecs*) are defined in different contexts using the following attributes:\n\n  * `@type`\n  * `@opaque`\n  * `@typep`\n  * `@spec`\n  * `@callback`\n  * `@macrocallback`\n\nIn addition, you can use `@typedoc` to document a custom `@type` definition.\n\nSee the \"User-defined types\" and \"Defining a specification\" sub-sections below for more information on defining types and typespecs.\n\n## A simple example\n\n    defmodule StringHelpers do\n      @typedoc \"A word from the dictionary\"\n      @type word() :: String.t()\n\n      @spec long_word?(word()) :: boolean()\n      def long_word?(word) when is_binary(word) do\n        String.length(word) > 8\n      end\n    end\n\nIn the example above:\n\n  * We declare a new type (`word()`) that is equivalent to the string type (`String.t()`).\n\n  * We describe the type using a `@typedoc`, which will be included in the generated documentation.\n\n  * We specify that the `long_word?/1` function takes an argument of type `word()` and\n    returns a boolean (`boolean()`), that is, either `true` or `false`.\n\n## Types and their syntax\n\nThe syntax Elixir provides for type specifications is similar to [the one in Erlang](https://www.erlang.org/doc/reference_manual/typespec.html). Most of the built-in types provided in Erlang (for example, `pid()`) are expressed in the same way: `pid()` (or simply `pid`). Parameterized types (such as `list(integer)`) are supported as well and so are remote types (such as [`Enum.t()`](`t:Enum.t/0`)). Integers and atom literals are allowed as types (for example, `1`, `:atom`, or `false`). All other types are built out of unions of predefined types. Some types can also be declared using their syntactical notation, such as `[type]` for lists, `{type1, type2, ...}` for tuples and `<<_ * _>>` for binaries.\n\nThe notation to represent the union of types is the pipe `|`. For example, the typespec `type :: atom() | pid() | tuple()` creates a type `type` that can be either an `atom`, a `pid`, or a `tuple`. This is usually called a [sum type](https://en.wikipedia.org/wiki/Tagged_union) in other languages\n\n> #### Differences with set-theoretic types {: .warning}\n>\n> While they do share some similarities, the types below do not map one-to-one\n> to the new types from the set-theoretic type system.\n>\n> For example, there is no plan to support subsets of the `integer()` type such\n> as positive, ranges or literals.\n>\n> Furthermore, set-theoretic types support the full range of set operations,\n> including intersections and negations.\n\n### Basic types\n\n    type ::\n          any()                     # the top type, the set of all terms\n          | none()                  # the bottom type, contains no terms\n          | atom()\n          | map()                   # any map\n          | pid()                   # process identifier\n          | port()                  # port identifier\n          | reference()\n          | tuple()                 # tuple of any size\n\n                                    ## Numbers\n          | float()\n          | integer()\n          | neg_integer()           # ..., -3, -2, -1\n          | non_neg_integer()       # 0, 1, 2, 3, ...\n          | pos_integer()           # 1, 2, 3, ...\n\n                                                                          ## Lists\n          | list(type)                                                    # proper list ([]-terminated)\n          | nonempty_list(type)                                           # non-empty proper list\n          | maybe_improper_list(content_type, termination_type)           # proper or improper list\n          | nonempty_improper_list(content_type, termination_type)        # improper list\n          | nonempty_maybe_improper_list(content_type, termination_type)  # non-empty proper or improper list\n\n          | Literals                # Described in section \"Literals\"\n          | BuiltIn                 # Described in section \"Built-in types\"\n          | Remotes                 # Described in section \"Remote types\"\n          | UserDefined             # Described in section \"User-defined types\"\n\n### Literals\n\nThe following literals are also supported in typespecs:\n\n    type ::                               ## Atoms\n          :atom                           # atoms: :foo, :bar, ...\n          | true | false | nil            # special atom literals\n\n                                          ## Bitstrings\n          | <<>>                          # empty bitstring\n          | <<_::size>>                   # size is 0 or a positive integer\n          | <<_::_*unit>>                 # unit is an integer from 1 to 256\n          | <<_::size, _::_*unit>>\n\n                                          ## (Anonymous) Functions\n          | (-> type)                     # zero-arity, returns type\n          | (type1, type2 -> type)        # two-arity, returns type\n          | (... -> type)                 # any arity, returns type\n\n                                          ## Integers\n          | 1                             # integer\n          | 1..10                         # integer from 1 to 10\n\n                                          ## Lists\n          | [type]                        # list with any number of type elements\n          | []                            # empty list\n          | [...]                         # shorthand for nonempty_list(any())\n          | [type, ...]                   # shorthand for nonempty_list(type)\n          | [key: value_type]             # keyword list with optional key :key of value_type\n\n                                                  ## Maps\n          | %{}                                   # empty map\n          | %{key: value_type}                    # map with required key :key of value_type\n          | %{key_type => value_type}             # map with required pairs of key_type and value_type\n          | %{required(key_type) => value_type}   # map with required pairs of key_type and value_type\n          | %{optional(key_type) => value_type}   # map with optional pairs of key_type and value_type\n          | %SomeStruct{}                         # struct with all fields of any type\n          | %SomeStruct{key: value_type}          # struct with required key :key of value_type\n\n                                          ## Tuples\n          | {}                            # empty tuple\n          | {:ok, type}                   # two-element tuple with an atom and any type\n\n### Built-in types\n\nThe following types are also provided by Elixir as shortcuts on top of the basic and literal types described above.\n\nBuilt-in type           | Defined as\n:---------------------- | :---------\n`term()`                | `any()`\n`arity()`               | `0..255`\n`as_boolean(t)`         | `t`\n`binary()`              | `<<_::_*8>>`\n`nonempty_binary()`     | `<<_::8, _::_*8>>`\n`bitstring()`           | `<<_::_*1>>`\n`nonempty_bitstring()`  | `<<_::1, _::_*1>>`\n`boolean()`             | `true` \\| `false`\n`byte()`                | `0..255`\n`char()`                | `0..0x10FFFF`\n`charlist()`            | `[char()]`\n`nonempty_charlist()`   | `[char(), ...]`\n`fun()`                 | `(... -> any)`\n`function()`            | `fun()`\n`identifier()`          | `pid()` \\| `port()` \\| `reference()`\n`iodata()`              | `iolist()` \\| `binary()`\n`iolist()`              | `maybe_improper_list(byte() \\| binary() \\| iolist(), binary() \\| [])`\n`keyword()`             | `[{atom(), any()}]`\n`keyword(t)`            | `[{atom(), t}]`\n`list()`                | `[any()]`\n`nonempty_list()`       | `nonempty_list(any())`\n`maybe_improper_list()` | `maybe_improper_list(any(), any())`\n`nonempty_maybe_improper_list()` | `nonempty_maybe_improper_list(any(), any())`\n`mfa()`                 | `{module(), atom(), arity()}`\n`module()`              | `atom()`\n`no_return()`           | `none()`\n`node()`                | `atom()`\n`number()`              | `integer()` \\| `float()`\n`struct()`              | `%{:__struct__ => atom(), optional(atom()) => any()}`\n`timeout()`             | `:infinity` \\| `non_neg_integer()`\n\n`as_boolean(t)` exists to signal users that the given value will be treated as a boolean, where `nil` and `false` will be evaluated as `false` and everything else is `true`. For example, `Enum.filter/2` has the following specification: `filter(t, (element -> as_boolean(term))) :: list`.\n\n### Remote types\n\nAny module is also able to define its own types and the modules in Elixir are no exception. For example, the `Range` module defines a `t/0` type that represents a range: this type can be referred to as `t:Range.t/0`. In a similar fashion, a string is `t:String.t/0`, and so on.\n\n### Maps\n\nThe key types in maps are allowed to overlap, and if they do, the leftmost key takes precedence.\nA map value does not belong to this type if it contains a key that is not in the allowed map keys.\n\nIf you want to denote that keys that were not previously defined in the map are allowed,\nit is common to end a map type with `optional(any) => any`.\n\nNote that the syntactic representation of `map()` is `%{optional(any) => any}`, not `%{}`. The notation `%{}` specifies the singleton type for the empty map.\n\n### Keyword Lists\n\nBeyond `keyword()` and `keyword(t)`, it can be helpful to compose a spec for an expected keyword list.\nFor example:\n\n```elixir\n@type option :: {:name, String.t} | {:max, pos_integer} | {:min, pos_integer}\n@type options :: [option()]\n```\n\nThis makes it clear that only these options are allowed, none are required, and order does not matter.\n\nIt also allows composition with existing types.\nFor example:\n\n```elixir\n@type option :: {:my_option, String.t()} | GenServer.option()\n\n@spec start_link([option()]) :: GenServer.on_start()\ndef start_link(opts) do\n  {my_opts, gen_server_opts} = Keyword.split(opts, [:my_option])\n  GenServer.start_link(__MODULE__, my_opts, gen_server_opts)\nend\n```\n\nThe following spec syntaxes are equivalent:\n\n```elixir\n@type options :: [{:name, String.t} | {:max, pos_integer} | {:min, pos_integer}]\n\n@type options :: [name: String.t, max: pos_integer, min: pos_integer]\n```\n\n### User-defined types\n\nThe `@type`, `@typep`, and `@opaque` module attributes can be used to define new types:\n\n    @type type_name :: type\n    @typep type_name :: type\n    @opaque type_name :: type\n\nA type defined with `@typep` is private. An opaque type, defined with `@opaque` is a type where the internal structure of the type will not be visible, but the type is still public.\n\nTypes can be parameterized by defining variables as parameters; these variables can then be used to define the type.\n\n    @type dict(key, value) :: [{key, value}]\n\n## Defining a specification\n\nA specification for a function can be defined as follows:\n\n    @spec function_name(type1, type2) :: return_type\n\nGuards can be used to restrict type variables given as arguments to the function.\n\n    @spec function(arg) :: [arg] when arg: atom\n\nIf you want to specify more than one variable, you separate them by a comma.\n\n    @spec function(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer\n\nType variables with no restriction can also be defined using `var`.\n\n    @spec function(arg) :: [arg] when arg: var\n\nThis guard notation only works with `@spec`, `@callback`, and `@macrocallback`.\n\nYou can also name your arguments in a typespec using `arg_name :: arg_type` syntax. This is particularly useful in documentation as a way to differentiate multiple arguments of the same type (or multiple elements of the same type in a type definition):\n\n    @spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer\n    @type color :: {red :: integer, green :: integer, blue :: integer}\n\nSpecifications can be overloaded, just like ordinary functions.\n\n    @spec function(integer) :: atom\n    @spec function(atom) :: integer\n\n## Behaviours\n\nBehaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*).\n\nA behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This \"interface\" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a \"server\" process will likely want to implement from the specific parts such as the actions that this server process has to perform.\n\nSay we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).\n\nWe can create a `Parser` behaviour:\n\n```elixir\ndefmodule Parser do\n  @doc \"\"\"\n  Parses a string.\n  \"\"\"\n  @callback parse(String.t) :: {:ok, term} | {:error, atom}\n\n  @doc \"\"\"\n  Lists all supported file extensions.\n  \"\"\"\n  @callback extensions() :: [String.t]\nend\n```\n\nAs seen in the example above, defining a callback is a matter of defining a specification for that callback, made of:\n\n  * the callback name (`parse` or `extensions` in the example)\n  * the arguments that the callback must accept (`String.t`)\n  * the *expected* type of the callback return value\n\nModules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above.\n\n### Implementing behaviours\n\nImplementing a behaviour is straightforward:\n\n```elixir\ndefmodule JSONParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some json \" <> str} # ... parse JSON\n\n  @impl Parser\n  def extensions, do: [\".json\"]\nend\n```\n\n```elixir\ndefmodule CSVParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some csv \" <> str} # ... parse CSV\n\n  @impl Parser\n  def extensions, do: [\".csv\"]\nend\n```\n\nIf a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.\n\nFurthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.\n\n```elixir\ndefmodule BADParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse, do: {:ok, \"something bad\"}\n\n  @impl Parser\n  def extensions, do: [\"bad\"]\nend\n```\n\nThis code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.\nYou can read more about `@impl` in the [module documentation](`Module#module-impl`).\n\n### Using behaviours\n\nBehaviours are useful because you can pass modules around as arguments and you can then *call back* to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:\n\n```elixir\n@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}\ndef parse_path(filename, parsers) do\n  with {:ok, ext} <- parse_extension(filename),\n       {:ok, parser} <- find_parser(ext, parsers),\n       {:ok, contents} <- File.read(filename) do\n    parser.parse(contents)\n  end\nend\n\ndefp parse_extension(filename) do\n  case Path.extname(filename) do\n    \"\" -> {:error, :no_extension}\n    ext -> {:ok, ext}\n  end\nend\n\ndefp find_parser(ext, parsers) do\n  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do\n    {:ok, parser}\n  else\n    {:error, :no_matching_parser}\n  end\nend\n```\n\nYou could also invoke any parser directly: `CSVParser.parse(...)`.\n\nNote you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.\n\n### Optional callbacks\n\nOptional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.\n\n> ### Unloaded modules {: .warning}\n>\n> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.\n\nOptional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:\n\n    defmodule MyBehaviour do\n      @callback vital_fun() :: any\n      @callback non_vital_fun() :: any\n      @macrocallback non_vital_macro(arg :: any) :: Macro.t\n      @optional_callbacks non_vital_fun: 0, non_vital_macro: 1\n    end\n\nOne example of optional callback in Elixir's standard library is `c:GenServer.format_status/1`.\n\n### Inspecting behaviours\n\nThe `@callback` and `@optional_callbacks` attributes are used to create a `behaviour_info/1` function available on the defining module. This function can be used to retrieve the callbacks and optional callbacks defined by that module.\n\nFor example, for the `MyBehaviour` module defined in \"Optional callbacks\" above:\n\n    MyBehaviour.behaviour_info(:callbacks)\n    #=> [vital_fun: 0, \"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n    MyBehaviour.behaviour_info(:optional_callbacks)\n    #=> [\"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n\nWhen using `iex`, the `IEx.Helpers.b/1` helper is also available.\n\n## Pitfalls\n\nThere are some known pitfalls when using typespecs, they are documented next.\n\n## The `string()` type\n\nElixir discourages the use of the `string()` type. The `string()` type refers to Erlang strings, which are known as \"charlists\" in Elixir. They do not refer to Elixir strings, which are UTF-8 encoded binaries. To avoid confusion, if you attempt to use the type `string()`, Elixir will emit a warning. You should use `charlist()`, `nonempty_charlist()`, `binary()` or `String.t()` accordingly, or any of the several literal representations for these types.\n\nNote that `String.t()` and `binary()` are equivalent to analysis tools. Although, for those reading the documentation, `String.t()` implies it is a UTF-8 encoded binary.\n\n## Functions which raise an error\n\nTypespecs do not need to indicate that a function can raise an error; any function can fail any time if given invalid input.\nIn the past, the Elixir standard library sometimes used `no_return()` to indicate this, but these usages have been removed.\n\nThe `no_return()` type also should not be used for functions which do return but whose purpose is a \"side effect\", such as `IO.puts/1`.\nIn these cases, the expected return type is `:ok`.\n\nInstead, `no_return()` should be used as the return type for functions which can never return a value.\nThis includes functions which loop forever calling `receive`, or which exist specifically to raise an error, or which shut down the VM.\n","isInternal":false,"tokens":4855,"sizeBytes":20633},{"name":"unicode-syntax.md","path":"lib/elixir/pages/references/unicode-syntax.md","rawUrl":"https://raw.githubusercontent.com/elixir-lang/elixir/HEAD/lib/elixir/pages/references/unicode-syntax.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Unicode syntax\n\nElixir supports Unicode throughout the language. This document is a complete reference of how\nElixir supports Unicode in its syntax.\n\nStrings (`\"olá\"`) and charlists (`'olá'`) support Unicode since Elixir v1.0. Strings are UTF-8 encoded. Charlists are lists of Unicode code points. In such cases, the contents are kept as written by developers, without any transformation.\n\nElixir also supports Unicode in variables, atoms, and calls since Elixir v1.5. The focus of this document is to provide a high-level introduction to how Elixir allows Unicode in its syntax. We also provide technical documentation describing how Elixir complies with the Unicode specification.\n\nTo check the Unicode version of your current Elixir installation, run `String.Unicode.version()`.\n\n## Introduction\n\nElixir allows Unicode characters in its variables, atoms, and calls. However, the Unicode characters must still obey the rules of the language syntax. In particular, variables and calls cannot start with an uppercase letter. From now on, we will refer to those terms as identifiers.\n\nThe characters allowed in identifiers are the ones specified by Unicode. Generally speaking, it is restricted to characters typically used by the writing system of human languages still in activity. In particular, it excludes symbols such as emojis, alternate numeric representations, musical notes, and the like.\n\nElixir imposes many restrictions on identifiers for security purposes. For example, the word \"josé\" can be written in two ways in Unicode: as the combination of the characters `j o s é` and as a combination of the characters `j o s e ́ `, where the accent is its own character. The former is called NFC form and the latter is the NFD form. Elixir normalizes all characters to be the in the NFC form.\n\nElixir also disallows mixed-scripts which are not explicitly separated by `_`. For example, it is not possible to name a variable `аdmin`, where `а` is in Cyrillic and the remaining characters are in Latin. Doing so will raise the following error:\n\n```text\n** (SyntaxError) invalid mixed-script identifier found: аdmin\n\nMixed-script identifiers are not supported for security reasons. 'аdmin' is made of the following scripts:\n\n  \\u0430 а {Cyrillic}\n  \\u0064 d {Latin}\n  \\u006D m {Latin}\n  \\u0069 i {Latin}\n  \\u006E n {Latin}\n\nMake sure all characters in the identifier resolve to a single script or a highly\nrestrictive script. See https://elixir.hexdocs.pm/unicode-syntax.html for more information.\n```\n\nFinally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.\n\nThat's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.\n\nFor the technical details, see the next sections that cover the technical Unicode requirements.\n\n## Unicode Standard Annex #31\n\nElixir conforms to the standards outlined in the [Unicode Standard Annex #31: Unicode Identifiers and Syntax](https://unicode.org/reports/tr31/), version 17.0.\n\n### R1. Default Identifiers\n\nThe general Elixir identifier rule is specified as:\n\n    <Identifier> := <Start> <Continue>* <Ending>?\n\nwhere `<Start>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> characters derived from the Unicode General Category of uppercase letters, lowercase letters, titlecase letters, modifier letters, other letters, letter numbers, plus `Other_ID_Start`, minus `Pattern_Syntax` and `Pattern_White_Space` code points\n>\n> In set notation: `[\\p{L}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\nand `<Continue>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> ID_Start characters, plus characters having the Unicode General Category of nonspacing marks, spacing combining marks, decimal number, connector punctuation, plus `Other_ID_Continue`, minus `Pattern_Syntax` and `Pattern_White_Space` code points.\n>\n> In set notation: `[\\p{ID_Start}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}\\p{Other_ID_Continue}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n`<Ending>` is an addition specific to Elixir that includes only the code points `?` (003F) and `!` (0021).\n\nThe spec also provides a `<Medial>` set, but Elixir does not include any character on this set. Therefore, the identifier rule has been simplified to consider this.\n\nElixir does not allow the use of ZWJ or ZWNJ in identifiers and therefore does not implement R1a. Bidirectional control characters are also not supported. R1b is guaranteed for backwards compatibility purposes.\n\n#### Atoms\n\nUnicode atoms in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Continue>` additionally includes the code point `@` (0040)\n\nNote atoms can also be quoted, which allows any characters, such as `:\"hello elixir\"`. All Elixir operators are also valid atoms, such as `:+`, `:@`, `:|>`, and others. The full description of valid atoms is available in the [\"Atoms\" section in the syntax reference](syntax-reference.md#atoms).\n\n#### Variables, local calls, and remote calls\n\nVariables in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Start>` additionally excludes Lu (letter uppercase) and Lt (letter titlecase) characters\n\nIn set notation: `[\\u{005F}\\p{Ll}\\p{Lm}\\p{Lo}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n#### Aliases\n\nAliases in Elixir only allow ASCII characters, starting in uppercase, and no punctuation characters.\n\n### R3. Pattern_White_Space and Pattern_Syntax Characters\n\nElixir supports only code points `\\t` (0009), `\\n` (000A), `\\r` (000D) and `\\s` (0020) as whitespace and therefore does not follow requirement R3. R3 requires a wider variety of whitespace and syntax characters to be supported.\n\n### R4. Equivalent Normalized Identifiers\n\nIdentifiers in Elixir are case sensitive.\n\nElixir normalizes all atoms and variables to NFC form. Quoted-atoms and strings can, however, be in any form and are not verified by the parser.\n\nIn other words, the atom `:josé` can only be written with the code points `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301`, but Elixir will rewrite it to the former (from Elixir 1.14). On the other hand, `:\"josé\"` may be written as `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301` and its form will be retained, since it is written between quotes.\n\nChoosing requirement R4 automatically excludes requirements R5, R6, and R7.\n\n## Unicode Technical Standard #39\n\nElixir conforms to the clauses outlined in the [Unicode Technical Standard #39](https://unicode.org/reports/tr39/) on Security, version 17.0.\n\n### C1. General Security Profile for Identifiers\n\nElixir will not allow tokenization of identifiers with codepoints in `\\p{Identifier_Status=Restricted}`, except for the outlined 'Additional normalizations' section below.\n\n> An implementation following the General Security Profile does not permit any characters in \\p{Identifier_Status=Restricted}, ...\n\nFor instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, is an uncommon codepoint and will trigger a warning.\n\n### C2. Confusable detection\n\nElixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.\n\nWe use the means described in Section 4, 'Confusable Detection', with one noted modification:\n\n> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.\n\nElixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).\n\n### C3. Mixed Script Detection\n\nElixir will not allow tokenization of mixed-script identifiers unless it is via chunks separated by an underscore, like `http_сервер`. We use the means described in Section 5.1, Mixed-Script Detection, to determine if script mixing is occurring, with the 'Additional Normalizations' documented in.\n\nExamples: Elixir allows an identifiers like `幻한`, even though it includes characters from multiple 'scripts', as Han characters may be mixed with Japanese and Korean, according to the rules from UTS 39 5.1. When mixing Latin and Japanese scripts, underscores are necessary, as in `:T_シャツ` (the Japanese word for 't-shirt' with an additional underscore separating the letter T).\n\nElixir does not allow code like `if аdmin, do: :ok, else: :err`, where the scriptset for the 'a' character is {Cyrillic} but all other characters have scriptsets of {Latin}. The scriptsets fail to resolve and a descriptive error is shown.\n\n### C4, C5 (inapplicable)\n\n'C4 - Restriction Level detection' conformance is not claimed and does not apply to identifiers in code; rather, it applies to classifying the level of safety of a given arbitrary string into one of 5 restriction levels.\n\n'C5 - Mixed number detection' conformance is inapplicable as Elixir does not support Unicode numbers.\n\n### Addition Normalizations\n\nAs of Elixir 1.14, some codepoints in `\\p{Identifier_Status=Restricted}` are *normalized* to other, unrestricted codepoints.\n\nThis is currently only applied to translate MICRO SIGN (`µ`) to Greek lowercase mu (`μ`).\n\nThe normalization avoids confusability and the mixed-script detection is modified to the extent that the normalized codepoint is given the union of scriptsets from both characters.\n\n  * For instance, in the example of MICRO => MU, MICRO was a 'Common'-script character - the same script given to the '_' underscore codepoint - and thus the normalized character's scriptset will be {Greek, Common}. 'Common' intersects with all non-empty scriptsets, and thus the normalized character can be used in tokens written in any script without causing script mixing.\n\n  * The code points normalized in this fashion are those that are in use in the community, and judged not likely to cause issues with unsafe script mixing. For instance, the MICRO or MU codepoint may be used in an atom or variable dealing with microseconds.\n","isInternal":false,"tokens":2585,"sizeBytes":11139},{"name":".cursorrules","path":".cursorrules (elixir-engineer-guidelines-cursorrules-prompt-file.mdc)","rawUrl":"https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/elixir-engineer-guidelines-cursorrules-prompt-file.mdc","title":"Awesome Cursorrules: elixir engineer guidelines","category":"cursor-rule","format":"markdown","content":"---\ndescription: \"Cursor rules for Elixir development with engineer guidelines.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: \nElixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n\nWhere:\n\ntype: One of the following:\n\nscope (optional): A noun describing a section of the codebase (e.g., fluxcd, deployment).\n\ndescription: A brief summary of the change in present tense.\n\nbody (optional): A more detailed explanation of the change.\n\nfooter (optional): One or more footers in the following format:\n","tokens":189,"sizeBytes":791}],"systemPromptSnippet":"<yakaai_skills repo=\"elixir-lang/elixir\">\n<!-- File: lib/elixir/pages/references/compatibility-and-deprecations.md (Tokens: ~6598 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Compatibility and deprecations\n\nElixir is versioned according to a vMAJOR.MINOR.PATCH schema.\n\nElixir is currently at major version v1. A new backwards compatible minor release happens every 6 months. Patch releases are not scheduled and are made whenever there are bug fixes or security patches.\n\nElixir applies bug fixes only to the latest minor branch. Security patches are available for the last 5 minor branches:\n\nElixir version | Support\n:------------- | :-----------------------------\n1.21           | Development\n1.20           | Bug fixes and security patches\n1.19           | Security patches only\n1.18           | Security patches only\n1.17           | Security patches only\n1.16           | Security patches only\n\nNew releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann) and on the [GitHub releases page](https://github.com/elixir-lang/elixir/releases).\n\nYou may also see [all releases](https://github.com/elixir-lang/elixir/releases) and [consult all disclosed vulnerabilities](https://github.com/elixir-lang/elixir/security) on GitHub.\n\nThere are currently no plans for a major v2 release.\n\n## Between non-major Elixir versions\n\nElixir minor and patch releases are backwards compatible: well-defined behaviors and documented APIs in a given version will continue working on future versions.\n\nAlthough we expect the vast majority of programs to remain compatible over time, it is impossible to guarantee that no future change will break any program. Under some unlikely circumstances, we may introduce changes that break existing code:\n\n  * Security: a security issue in the implementation may arise whose resolution requires backwards incompatible changes. We reserve the right to address such security issues.\n\n  * Bugs: if an API has undesired behavior, a program that depends on the buggy behavior may break if the bug is fixed. We reserve the right to fix such bugs.\n\n  * Compiler front-end: improvements may be done to the compiler, introducing new warnings for ambiguous modes and providing more detailed error messages. Those can lead to compilation errors (when running with `--warnings-as-errors`) or tooling failures when asserting on specific error messages (although one should avoid such). We reserve the right to do such improvements.\n\n  * Imports: new functions may be added to the `Kernel` module, which is auto-imported. They may collide with local functions defined in your modules. Collisions can be resolved in a backwards compatible fashion using `import Kernel, except: [...]` with a list of all functions you don't want to be imported from `Kernel`. We reserve the right to do such additions.\n\nIn order to continue evolving the language without introducing breaking changes, Elixir will rely on deprecations to demote certain practices and promote new ones. Our deprecation policy is outlined in the [\"Deprecations\" section](#deprecations).\n\nThe only exception to the compatibility guarantees above are experimental features, which will be explicitly marked as such, and do not provide any compatibility guarantee until they are stabilized.\n\n## Between Elixir and Erlang/OTP\n\nErlang/OTP versioning is independent from the versioning of Elixir. Erlang releases a new major version yearly. Our goal is to support the last three Erlang major versions by the time Elixir is released. The compatibility table is shown below.\n\nElixir version | Supported Erlang/OTP versions\n:------------- | :-------------------------------\n1.21           | 27 - 29\n1.20           | 27 - 29\n1.19           | 26 - 28\n1.18           | 25 - 27\n1.17           | 25 - 27\n1.16           | 24 - 26\n1.15           | 24 - 26\n1.14           | 23 - 25 (and Erlang/OTP 26 from v1.14.5)\n1.13           | 22 - 24 (and Erlang/OTP 25 from v1.13.4)\n1.12           | 22 - 24\n1.11           | 21 - 23 (and Erlang/OTP 24 from v1.11.4)\n1.10           | 21 - 22 (and Erlang/OTP 23 from v1.10.3)\n1.9            | 20 - 22\n1.8            | 20 - 22\n1.7            | 19 - 22\n1.6            | 19 - 20 (and Erlang/OTP 21 from v1.6.6)\n1.5            | 18 - 20\n1.4            | 18 - 19 (and Erlang/OTP 20 from v1.4.5)\n1.3            | 18 - 19\n1.2            | 18 - 18 (and Erlang/OTP 19 from v1.2.6)\n1.1            | 17 - 18\n1.0            | 17 - 17 (and Erlang/OTP 18 from v1.0.5)\n\nElixir may add compatibility to new Erlang/OTP versions on patch releases, such as support for Erlang/OTP 20 in v1.4.5. Those releases are made for convenience and typically contain the minimum changes for Elixir to run without errors, if any changes are necessary. Only the next minor release, in this case v1.5.0, effectively leverages the new features provided by the latest Erlang/OTP release.\n\n## Deprecations\n\n### Policy\n\nElixir deprecations happen in 3 steps:\n\n  1. The feature is soft-deprecated. It means both CHANGELOG and documentation must list the feature as deprecated but no warning is effectively emitted by running the code. There is no requirement to soft-deprecate a feature.\n\n  2. The feature is effectively deprecated by emitting warnings on usage. This is also known as hard-deprecation. In order to deprecate a feature, the proposed alternative MUST exist for AT LEAST THREE minor versions. For example, `Enum.uniq/2` was soft-deprecated in favor of `Enum.uniq_by/2` in Elixir v1.1. This means a deprecation warning may only be emitted by Elixir v1.4 or later.\n\n  3. The feature is removed. This can only happen on major releases. This means deprecated features in Elixir v1.x shall only be removed by Elixir v2.x.\n\n### Table of deprecations\n\nThe first column is the version the feature was hard deprecated. The second column shortly describes the deprecated feature and the third column explains the replacement and from which the version the replacement is available from.\n\nVersion | Deprecated feature                                  | Replaced by (available since)\n:-------| :-------------------------------------------------- | :---------------------------------------------------------------\n[v1.21] | `Macro.Env.fetch_alias/2` (and `fetch_macro_alias`) | `Macro.Env.expand_alias/4` (v1.17)\n[v1.20] | `<<x::size(y)>>` in patterns without `^`            | `<<x::size(^y)>>` (v1.15)\n[v1.20] | `File.stream!(path, modes, lines_or_bytes)`         | `File.stream!(path, lines_or_bytes, modes)` (v1.16)\n[v1.20] | `Kernel.ParallelCompiler.async/1`                   | `Kernel.ParallelCompiler.pmap/2` (v1.16)\n[v1.20] | `Logger.*_backend` functions                        | The `LoggerBackends` module from [`:logger_backends`](https://hex.pm/packages/logger_backends) package\n[v1.20] | `Logger.enable/1` and `Logger.disable/1`            | `Logger.put_process_level/2` and `Logger.delete_process_level/1` respectively (v1.15)\n[v1.19] | CLI configuration in `def project` inside `mix.exs` | Moving it to `def cli` (v1.14)\n[v1.19] | Using `,` to separate tasks in `mix do`             | Using `+` (v1.14)\n[v1.19] | `Logger`'s `:backends` configuration                | `Logger`'s `:default_handler` configuration (v1.15)\n[v1.19] | Passing a callback to `File.cp/3`, `File.cp!/3`, `File.cp_r/3`, and `File.cp_r!/3` | The `:on_conflict` option (v1.14)\n[v1.18] | `<%#` in EEx                                        | `<%!--` (v1.14) or `<% #` (v1.0)\n[v1.18] | `EEx.Engine.handle_text/2` callback in EEx          | `c:EEx.Engine.handle_text/3` (v1.14)\n[v1.18] | Returning a 2-arity function from `Enumerable.slice/1` | Returning a 3-arity function (v1.14)\n[v1.18] | Ranges with negative steps in `Range.new/2`         | Explicit steps in ranges (v1.11)\n[v1.18] | `Tuple.append/2`                                    | `Tuple.insert_at/3` (v1.0)\n[v1.18] | `mix cmd --app APP`                                 | `mix do --app APP` (v1.14)\n[v1.18] | `List.zip/1`                                        | `Enum.zip/1` (v1.0)\n[v1.18] | `Module.eval_quoted/3`                              | `Code.eval_quoted/3` (v1.0)\n[v1.17] | Single-quoted charlists (`'foo'`)                   | `~c\"foo\"` (v1.0)\n[v1.17] | `left..right` in patterns and guards                | `left..right//step` (v1.11)\n[v1.17] | `ExUnit.Case.register_test/4`                       | `register_test/6` (v1.10)\n[v1.17] | `:all` in `IO.read/2` and `IO.binread/2`            | `:eof` (v1.13)\n[v1.16] | `~R/.../`                                           | `~r/.../` (v1.0)\n[v1.16] | Ranges with negative steps in `Enum.slice/2`        | Explicit steps in ranges (v1.11)\n[v1.16] | Ranges with negative steps in `String.slice/2`      | Explicit steps in ranges (v1.11)\n[v1.15] | `Calendar.ISO.day_of_week/3`                        | `Calendar.ISO.day_of_week/4` (v1.11)\n[v1.15] | `Exception.exception?/1`                            | `Kernel.is_exception/1` (v1.11)\n[v1.15] | `Regex.regex?/1`                                    | `Kernel.is_struct/2` (`Kernel.is_struct(term, Regex)`) (v1.11)\n[v1.15] | `Logger.warn/2`                                     | `Logger.warning/2` (v1.11)\n[v1.14] | `use Bitwise`                                       | `import Bitwise` (v1.0)\n[v1.14] | `~~~/1`                                             | `bnot/1` (v1.0)\n[v1.14] | `Application.get_env/3` and similar in module body  | `Application.compile_env/3` (v1.10)\n[v1.14] | Compiled patterns in `String.starts_with?/2`        | Pass a list of strings instead (v1.0)\n[v1.14] | `Mix.Tasks.Xref.calls/1`                            | Compilation tracers (outlined in `Code`) (v1.10)\n[v1.14] | `$levelpad` in Logger                               | *None*\n[v1.14] | `<\\|>` as a custom operator                         | Another custom operator (v1.0)\n[v1.13] | `!` and `!=` in Version requirements                | `~>` or `>=` (v1.0)\n[v1.13] | `Mix.Config`                                        | `Config` (v1.9)\n[v1.13] | `:strip_beam` config to `mix escript.build`         | `:strip_beams` (v1.9)\n[v1.13] | `Macro.to_string/2`                                 | `Macro.to_string/1` (v1.0)\n[v1.13] | `System.get_pid/0`                                  | `System.pid/0` (v1.9)\n[v1.12] | `^^^/2`                                             | `bxor/2` (v1.0)\n[v1.12] | `@foo()` to read module attributes                  | Remove the parenthesis (v1.0)\n[v1.12] | `use EEx.Engine`                                    | Explicitly delegate to EEx.Engine instead (v1.0)\n[v1.12] | `:xref` compiler in Mix                             | Nothing (it always runs as part of the compiler now)\n[v1.11] | `Mix.Project.compile/2`                             | `Mix.Task.run(\"compile\", args)` (v1.0)\n[v1.11] | `Supervisor.Spec.worker/3` and `Supervisor.Spec.supervisor/3` | The new child specs outlined in `Supervisor` (v1.5)\n[v1.11] | `Supervisor.start_child/2` and `Supervisor.terminate_child/2` | `DynamicSupervisor` (v1.6)\n[v1.11] | `System.stacktrace/0`                               | `__STACKTRACE__` in `try/catch/rescue` (v1.7)\n[v1.10] | `Code.ensure_compiled?/1`                           | `Code.ensure_compiled/1` (v1.0)\n[v1.10] | `Code.load_file/2`                                  | `Code.require_file/2` (v1.0) or `Code.compile_file/2` (v1.7)\n[v1.10] | `Code.loaded_files/0`                               | `Code.required_files/0` (v1.7)\n[v1.10] | `Code.unload_file/1`                                | `Code.unrequire_files/1` (v1.7)\n[v1.10] | Passing non-chardata to `Logger.log/2`              | Explicitly convert to string with `to_string/1` (v1.0)\n[v1.10] | `:compile_time_purge_level` in `Logger` app environment | `:compile_time_purge_matching` in `Logger` app environment (v1.7)\n[v1.10] | `Supervisor.Spec.supervise/2`                       | The new child specs outlined in `Supervisor` (v1.5)\n[v1.10] | `:simple_one_for_one` strategy in `Supervisor`      | `DynamicSupervisor` (v1.6)\n[v1.10] | `:restart` and `:shutdown` in `Task.Supervisor.start_link/1` | `:restart` and `:shutdown` in `Task.Supervisor.start_child/3` (v1.6)\n[v1.9]  | Enumerable keys in `Map.drop/2`, `Map.split/2`, and `Map.take/2` | Call `Enum.to_list/1` on the second argument before hand (v1.0)\n[v1.9]  | `Mix.Project.load_paths/1`                          | `Mix.Project.compile_path/1` (v1.0)\n[v1.9]  | Passing `:insert_replaced` to `String.replace/4`    | Use `:binary.replace/4` (v1.0)\n[v1.8]  | Passing a non-empty list to `Collectable.into/1`    | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `:into` in `for/1`      | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Passing a non-empty list to `Enum.into/2`           | `++/2` or `Keyword.merge/2` (v1.0)\n[v1.8]  | Time units in its plural form, such as: `:seconds`, `:milliseconds`, and the like | Use the singular form, such as: `:second`, `:millisecond`, and so on (v1.4)\n[v1.8]  | `Inspect.Algebra.surround/3`                        | `Inspect.Algebra.concat/2` and `Inspect.Algebra.nest/2` (v1.0)\n[v1.8]  | `Inspect.Algebra.surround_many/6`                   | `Inspect.Algebra.container_doc/6` (v1.6)\n[v1.9]  | `--detached` in `Kernel.CLI`                        | `--erl \"-detached\"` (v1.0)\n[v1.8]  | `Kernel.ParallelCompiler.files/2`                   | `Kernel.ParallelCompiler.compile/2` (v1.6)\n[v1.8]  | `Kernel.ParallelCompiler.files_to_path/2`           | `Kernel.ParallelCompiler.compile_to_path/2` (v1.6)\n[v1.8]  | `Kernel.ParallelRequire.files/2`                    | `Kernel.ParallelCompiler.require/2` (v1.6)\n[v1.8]  | Returning `{:ok, contents}` or `:error` from `Mix.Compilers.Erlang.compile/6`'s callback | Return `{:ok, contents, warnings}` or `{:error, errors, warnings}` (v1.6)\n[v1.8]  | `System.cwd/0` and `System.cwd!/0`                  | `File.cwd/0` and `File.cwd!/0` respectively (v1.0)\n[v1.7]  | `Code.get_docs/2`                                   | `Code.fetch_docs/1` (v1.7)\n[v1.7]  | `Enum.chunk/2,3,4`                                  | `Enum.chunk_every/2` and [`Enum.chunk_every/3,4`](`Enum.chunk_every/4`) (v1.5)\n[v1.7]  | Calling `super/1` in`GenServer` callbacks           | Implementing the behaviour explicitly without calling `super/1` (v1.0)\n[v1.7]  | [`not left in right`](`in/2`)                | [`left not in right`](`in/2`) (v1.5)\n[v1.7]  | `Registry.start_link/3`                             | `Registry.start_link/1` (v1.5)\n[v1.7]  | `Stream.chunk/2,3,4`                                | `Stream.chunk_every/2` and [`Stream.chunk_every/3,4`](`Stream.chunk_every/4`) (v1.5)\n[v1.6]  | `Enum.partition/2`                                  | `Enum.split_with/2` (v1.4)\n[v1.6]  | `Macro.unescape_tokens/1,2`                         | Use `Enum.map/2` to traverse over the arguments (v1.0)\n[v1.6]  | `Module.add_doc/6`                                  | [`@doc`](`Module`) module attribute (v1.0)\n[v1.6]  | `Range.range?/1`                                    | Pattern match on [`_.._`](`../2`) (v1.0)\n[v1.5]  | `()` to mean `nil`                                  | `nil` (v1.0)\n[v1.5]  | `char_list/0` type                                  | `t:charlist/0` type (v1.3)\n[v1.5]  | `Atom.to_char_list/1`                               | `Atom.to_charlist/1` (v1.3)\n[v1.5]  | `Enum.filter_map/3`                                 | `Enum.filter/2` + `Enum.map/2` or `for/1` comprehensions (v1.0)\n[v1.5]  | `Float.to_char_list/1`                              | `Float.to_charlist/1` (v1.3)\n[v1.5]  | `GenEvent` module                                   | `Supervisor` and `GenServer` (v1.0)\n[v1.5]  | `<%=` in middle and end expressions in `EEx`        | Use `<%` (`<%=` is allowed only in start expressions) (v1.0)\n[v1.5]  | `:as_char_lists` value in `t:Inspect.Opts.t/0` type | `:as_charlists` value (v1.3)\n[v1.5]  | `:char_lists` key in `t:Inspect.Opts.t/0` type      | `:charlists` key (v1.3)\n[v1.5]  | `Integer.to_char_list/1,2`                          | `Integer.to_charlist/1` and `Integer.to_charlist/2` (v1.3)\n[v1.5]  | `to_char_list/1`                                    | `to_charlist/1` (v1.3)\n[v1.5]  | `List.Chars.to_char_list/1`                         | `List.Chars.to_charlist/1` (v1.3)\n[v1.5]  | `@compile {:parse_transform, _}` in `Module`        | *None*\n[v1.5]  | `Stream.filter_map/3`                               | `Stream.filter/2` + `Stream.map/2` (v1.0)\n[v1.5]  | `String.ljust/3` and `String.rjust/3`               | Use `String.pad_leading/3` and `String.pad_trailing/3` with a binary padding (v1.3)\n[v1.5]  | `String.lstrip/1` and `String.rstrip/1`             | `String.trim_leading/1` and `String.trim_trailing/1` (v1.3)\n[v1.5]  | `String.lstrip/2` and `String.rstrip/2`             | Use `String.trim_leading/2` and `String.trim_trailing/2` with a binary as second argument (v1.3)\n[v1.5]  | `String.strip/1` and `String.strip/2`               | `String.trim/1` and `String.trim/2` (v1.3)\n[v1.5]  | `String.to_char_list/1`                             | `String.to_charlist/1` (v1.3)\n[v1.4]  | Anonymous functions with no expression after `->`   | Use an expression or explicitly return `nil` (v1.0)\n[v1.4]  | Support for making [private functions](`defp/2`) overridable | Use [public functions](`def/2`) (v1.0)\n[v1.4]  | Variable used as function call                      | Use parentheses (v1.0)\n[v1.4]  | `Access.key/1`                                      | `Access.key/2` (v1.3)\n[v1.4]  | `Behaviour` module                                  | `@callback` module attribute (v1.0)\n[v1.4]  | `Enum.uniq/2`                                       | `Enum.uniq_by/2` (v1.2)\n[v1.4]  | `Float.to_char_list/2`                              | `:erlang.float_to_list/2` (Erlang/OTP 17)\n[v1.4]  | `Float.to_string/2`                                 | `:erlang.float_to_binary/2` (Erlang/OTP 17)\n[v1.4]  | `HashDict` module                                   | `Map` (v1.2)\n[v1.4]  | `HashSet` module                                    | `MapSet` (v1.1)\n[v1.4]  | `IEx.Helpers.import_file/2`                         | `IEx.Helpers.import_file_if_available/1` (v1.3)\n[v1.4]  | `Mix.Utils.camelize/1`                              | `Macro.camelize/1` (v1.2)\n[v1.4]  | `Mix.Utils.underscore/1`                            | `Macro.underscore/1` (v1.2)\n[v1.4]  |  Multi-letter aliases in `OptionParser`             | Use single-letter aliases (v1.0)\n[v1.4]  | `Set` module                                        | `MapSet` (v1.1)\n[v1.4]  | `Stream.uniq/2`                                     | `Stream.uniq_by/2` (v1.2)\n[v1.3]  | `\\x{X*}` inside strings/sigils/charlists            | `\\uXXXX` or `\\u{X*}` (v1.1)\n[v1.3]  | `Dict` module                                       | `Keyword` (v1.0) or `Map` (v1.2)\n[v1.3]  | `:append_first` option in `defdelegate/2`           | Define the function explicitly (v1.0)\n[v1.3]  | Map/dictionary as 2nd argument in `Enum.group_by/3` | `Enum.reduce/3` (v1.0)\n[v1.3]  | `Keyword.size/1`                                    | `length/1` (v1.0)\n[v1.3]  | `Map.size/1`                                        | `map_size/1` (v1.0)\n[v1.3]  | `/r` option in `Regex`                              | `/U` (v1.1)\n[v1.3]  | `Set` behaviour                                     | `MapSet` data structure (v1.1)\n[v1.3]  | `String.valid_character?/1`                         | `String.valid?/1` (v1.0)\n[v1.3]  | `Task.find/2`                                       | Use direct message matching (v1.0)\n[v1.3]  | Non-map as 2nd argument in `URI.decode_query/2`     | Use a map (v1.0)\n[v1.2]  | `Dict` behaviour                                    | `Map` and `Keyword` (v1.0)\n[v1.1]  | `?\\xHEX`                                            | `0xHEX` (v1.0)\n[v1.1]  | `Access` protocol                                   | `Access` behaviour (v1.1)\n[v1.1]  | `as: true \\| false` in `alias/2` and `require/2`    | *None*\n\n[v1.1]: https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md#4-deprecations\n[v1.2]: https://github.com/elixir-lang/elixir/blob/v1.2/CHANGELOG.md#changelog-for-elixir-v12\n[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations\n[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations\n[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations\n[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations\n[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations\n[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations\n[v1.9]: https://github.com/elixir-lang/elixir/blob/v1.9/CHANGELOG.md#4-hard-deprecations\n[v1.10]: https://github.com/elixir-lang/elixir/blob/v1.10/CHANGELOG.md#4-hard-deprecations\n[v1.11]: https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md#4-hard-deprecations\n[v1.12]: https://github.com/elixir-lang/elixir/blob/v1.12/CHANGELOG.md#4-hard-deprecations\n[v1.13]: https://github.com/elixir-lang/elixir/blob/v1.13/CHANGELOG.md#4-hard-deprecations\n[v1.14]: https://github.com/elixir-lang/elixir/blob/v1.14/CHANGELOG.md#4-hard-deprecations\n[v1.15]: https://github.com/elixir-lang/elixir/blob/v1.15/CHANGELOG.md#4-hard-deprecations\n[v1.16]: https://github.com/elixir-lang/elixir/blob/v1.16/CHANGELOG.md#4-hard-deprecations\n[v1.17]: https://github.com/elixir-lang/elixir/blob/v1.17/CHANGELOG.md#4-hard-deprecations\n[v1.18]: https://github.com/elixir-lang/elixir/blob/v1.18/CHANGELOG.md#4-hard-deprecations\n[v1.19]: https://github.com/elixir-lang/elixir/blob/v1.19/CHANGELOG.md#4-hard-deprecations\n[v1.20]: https://github.com/elixir-lang/elixir/blob/v1.20/CHANGELOG.md#4-hard-deprecations\n[v1.21]: https://github.com/elixir-lang/elixir/blob/main/CHANGELOG.md#4-hard-deprecations\n\n<!-- File: lib/elixir/pages/references/gradual-set-theoretic-types.md (Tokens: ~4713 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Gradual set-theoretic types\n\nElixir is in the process of incorporating set-theoretic types into the compiler. This document outlines the current stage of our implementation for this Elixir version. Elixir's type system is:\n\n  * **sound** - the inferred and assigned by the type system align with the behaviour of the program\n\n  * **gradual** - Elixir's type system includes the `dynamic()` type, which can be used when the type of a variable or expression is checked at runtime. However, instead of simply discarding all typing information, Elixir's `dynamic()` type works as a range. For example, if you write `dynamic(integer() or binary())`, Elixir's type system will still emit violations if none of those types are accepted. Furthermore, in the absence of `dynamic()`, Elixir's type system behaves as a static one\n\n  * **developer friendly** - the types are described, implemented, and composed using basic set operations: unions, intersections, and negation (hence it is a set-theoretic type system)\n\nThe current milestone aims to infer types from existing programs and use them for type checking, enabling the Elixir compiler to find faults and bugs in codebases without requiring changes to existing software. User provided type signatures are planned for future releases. The underlying principles, theory, and roadmap of our work have been outlined in [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391).\n\n## A gentle introduction\n\nTypes in Elixir are written using the type named followed by parentheses, such as `integer()` or `list(integer())`.\n\nThe basic types are:\n\n```elixir\natom()\nbinary()\nbitstring()\nempty_list()\ninteger()\nfloat()\nfunction()\nmap()\nnon_empty_list(elem_type, tail_type)\npid()\nport()\nreference()\ntuple()\n```\n\nMany of the types above can also be written more precisely. We will discuss their syntax in the next sections, but here are two examples:\n\n  * While `atom()` represents all atoms, the atom `:ok` can also be represented in the type system as `:ok`\n\n  * While `tuple()` represents all tuples, you can specify the type of a two-element tuple where the first element is the atom `:ok` and the second is an integer as `{:ok, integer()}`\n\nThere are also three special types: `none()` (represents an empty set), `term()` (represents all types), `dynamic()` (represents a range of the given types).\n\nGiven the types are set-theoretic, we can compose them using unions (`or`), intersections (`and`), and negations (`not`). For example, to say a function returns either atoms or integers, one could write: `atom() or integer()`.\n\nIntersections will find the elements in common between the operands. For example, `atom() and integer()`, which in this case is the empty set `none()`. You can combine intersections and negations to perform difference, for example, to say that a function expects all atoms, except `nil` (which is an atom), you could write: `atom() and not nil`.\n\nYou can find a complete reference in the [set-theoretic types cheatsheet](../cheatsheets/types-cheat.cheatmd).\n\n## The syntax of data types\n\nIn this section we will cover the syntax of all data types. At the moment, developers will interact with those types mostly through compiler warnings and diagnostics.\n\n### Broad types\n\nThese types are broad in that they cannot represent individual elements, only the whole set. For example, the numbers `1` and `42` are both represented by the type `integer()`.\n\nThey are: `binary()`, `bitstring()`, `integer()`, `float()`, `pid()`, `port()`, `reference()`.\n\nThe `binary()` type is a subtype of the less frequently used `bitstring()` type, as binaries are bitstrings where the number of bits is divisible by 8.\n\n### Atoms\n\nYou can represent all atoms as `atom()`. You can also represent each individual atom using their literal syntax. For instance, the atom `:foo` and `:hello_world` are also valid (distinct) types.\n\n`nil`, `true`, and `false` are also atoms and can be written as is. `boolean()` is a convenience type alias that represents `true or false`.\n\n### Tuples\n\nYou can represent all tuples as `tuple()`. Tuples may also be written using the curly brackets syntax, such as `{:ok, binary()}`.\n\nYou may use `...` at the end of the tuple to imply the overall size of the tuple is unknown. For example, the following tuple has at least two elements: `{:ok, binary(), ...}`.\n\n### Lists\n\nYou can represent all _proper_ lists as `list()`, which also includes the empty list.\n\nYou can also specify the type of the list element as argument. For example, `list(integer())` represents the values `[]` and `[1, 2, 3]`, but not `[1, \"two\", 3]`.\n\nInternally, Elixir represents the type `list(a)` as the union two distinct types, `empty_list()` and `non_empty_list(a)`. In other words, `list(integer())` is equivalent to `empty_list() or non_empty_list(integer())`.\n\n#### Improper lists\n\nWhile most developers will simply use `list(a)`, the type system can express all different representations of lists in Elixirby passing a second argument to `non_empty_list`, which represents the type of the tail.\n\nA proper list is one where the tail is the empty list itself. The type `non_empty_list(integer())` is equivalent to `non_empty_list(integer(), empty_list())`.\n\nIf the `tail_type` is anything but a list, then we have an improper list. For example, the value `[1, 2 | 3]` would have the type `non_empty_list(integer(), integer())`.\n\nIf you pass a list type as the tail, then the list type is merged into the element type. For example, `non_empty_list(integer(), list(binary()))` is the same as `non_empty_list(integer() or binary(), empty_list())`.\n\n### Maps\n\nYou can represent all maps as `map()`.\n\nMaps may also be written using their literal syntax:\n\n```elixir\n%{name: binary(), age: integer()}\n```\n\nwhich outlines a map with exactly two keys, `:name` and `:age`, and values of type `binary()` and `integer()` respectively. We say the map above is \"closed\": it only supports the keys explicitly defined. We can also mark a map as \"open\", by including `...` as its first element:\n\n```elixir\n%{..., name: binary(), age: integer()}\n```\n\nThe type above says the keys `:name` and `:age` must exist, with their respective types, but other keys may be present. The `map()` type is the same as `%{...}`. For the empty map, you may write `%{}`, although we recommend using `empty_map()` for clarity.\n\n#### Optional keys\n\nA key may be marked as optional using the `if_set/1` operation on its value type:\n\n```elixir\n%{name: binary(), age: if_set(integer())}\n```\n\nis a map that certainly has the `:name` key but it may have the `:age` key (and if it has such key, its value type is `integer()`).\n\nYou can also use `not_set()` to denote a key cannot be present:\n\n```elixir\n%{..., age: not_set()}\n```\n\nThe type above says the map may have any key, except the `:age` one. This is, for instance, the type returned by `Map.delete(map, :age)`.\n\n#### Domain types\n\nIn the examples above, all map keys were atoms, but we can also use other types as map keys. For example:\n\n```elixir\n# Closed map\n%{binary() or atom() => integer()}\n\n# Open map\n%{..., binary() or atom() => integer()}\n```\n\nCurrently, the type system only tracks the top of each individual type as the domain keys. For example, if you say:\n\n```elixir\n%{list(integer()) => integer(), list(binary()) => binary()}\n```\n\nThat's the same as specifying all lists:\n\n```elixir\n%{list() => integer() or binary()}\n```\n\nThe supported domain keys are `atom()`, `bitstring()`, `binary()`, `integer()`, `float()`, `fun()`, `list()`, `map()`, `pid()`, `port()`, `reference()`, and `tuple()`. In the case of maps, the `bitstring()` domain stores exclusively keys which are not binary. The ones which are `binary()` are stored under the `binary()` domain.\n\nFurthermore, it is important to note that domain keys are, by definition, optional. Whenever you have a `%{integer() => integer()}`and you try to fetch a key, we must assume the key may not exist (after all, it is not possible to store all integers as map keys as they are infinite).\n\n#### Mixed keys\n\nIt is also possible to mix domain and atom keys. For example, the following map says that all atom keys are of type `binary()`, except the `:root` key, which has type `integer()`:\n\n```elixir\n# Closed map\n%{atom() => binary(), root: integer()}\n\n# Open map\n%{..., atom() => binary(), root: integer()}\n```\n\nThe order of the keys is of increasing precision. `:root` is more precise than `atom()`, therefore it comes later. This mirrors the runtime semantics of maps, where duplicate keys override the value of earlier ones.\n\n### Functions\n\nYou can represent all functions as `function()`.  However, in practice, most functions are represented as arrows. For example, a function that receives an integer and return boolean would be written as `(integer() -> boolean())`. A function that receives two integers and return a string (i.e. a binary) would be written as `(integer(), integer() -> binary())`.\n\nWhen representing functions with multiple clauses, which may take different input types, we use intersections. For example, imagine the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nIf you give it an integer, it negates it. If you give it a boolean, it negates it.\n\nWe can say this function has the type `(integer() -> integer())` because it is capable of receiving an integer and returning an integer. In this case, `(integer() -> integer())` is a set that represents all functions that can receive an integer and return an integer. Even though this function can receive other arguments and return other values, it is still part of the `(integer() -> integer())` set.\n\nThis function also has the type `(boolean() -> boolean())`, because it also receives booleans and returns booleans. If you pass the function above to another function that expects `(boolean() -> boolean())`, type checking will succeed. Therefore, we can say the overall type of the function is `(integer() -> integer()) and (boolean() -> boolean())`. The intersection means the function belongs to both sets.\n\nAt this point, you may ask, why not a union? As a real-world example, take a t-shirt with green and yellow stripes. We can say the t-shirt belongs to the set of \"t-shirts with green color\". We can also say the t-shirt belongs to the set of \"t-shirts with yellow color\". Let's see the difference between unions and intersections:\n\n  * `(t_shirts_with_green() or t_shirts_with_yellow())` - contains t-shirts with either green or yellow, such as green, green and red, green and yellow, but also only yellow, yellow and red, etc.\n\n  * `(t_shirts_with_green() and t_shirts_with_yellow())` - contains t-shirts with both green and yellow (and maybe other colors)\n\nSince the t-shirt has both colors, we could say it belongs to the union of green and yellow t-shirts, but doing so would not capture the fact it is both green and yellow. Therefore it is more precise to say it belongs to the intersection of both sets. The same way that a function that goes from `(integer() -> integer())` and `(boolean() -> boolean())` is also an intersection. In practice, it is not useful to define the union of two functions in Elixir, so the compiler will point you to the right direction if you specify the wrong one.\n\n## The `dynamic()` type\n\nExisting Elixir programs do not have type declarations, but we still want to be able to type check them. This is done with the introduction of the `dynamic()` type.\n\nWhen Elixir sees the following function:\n\n```elixir\ndef negate(x) when is_integer(x), do: -x\ndef negate(x) when is_boolean(x), do: not x\n```\n\nElixir type checks it as if the function had the type `(dynamic() -> dynamic())`. Then, based on patterns and guards, we can refine the value of the variable `x` to be `dynamic() and integer()` and `dynamic() and boolean()` for each clause respectively. We say `dynamic()` is a gradual type, which leads us to _gradual set-theoretic types_.\n\nThe simplest way to reason about `dynamic()` in Elixir is that it is a range of types. If you have a type `atom() or integer()`, the underlying code needs to work with both `atom() or integer()`. For example, if you call `Integer.to_string(var)`, and `var` has type `atom() or integer()`, the type system will emit a warning, because `Integer.to_string/1` does not accept atoms.\n\nHowever, by intersecting a type with `dynamic()`, we make the type gradual and therefore only a subset of the type needs to be valid. For instance, if you call `Integer.to_string(var)`, and `var` has type `dynamic() and (atom() or integer())`, the type system will not emit a warning, because `Integer.to_string/1` works with at least one of the types. For convenience, most programs will write `dynamic(atom() or integer())` instead of the intersection. They are equivalent.\n\nCompared to other gradually typed languages, the `dynamic()` type in Elixir is quite powerful: it restricts our program to certain types, via intersections, while still emitting warnings once it is certain the code will fail. This makes `dynamic()` an excellent tool for typing existing Elixir code with meaningful warnings.\n\nIf the user provides their own types, and those types are not `dynamic()`, then Elixir's type system behaves as a statically typed one. This brings us to one last property of dynamic types in Elixir: dynamic types are always at the root. For example, when you write a tuple of type `{:ok, dynamic()}`, Elixir will rewrite it to `dynamic({:ok, term()})`. While this has the downside that you cannot make part of a tuple/map/list gradual, only the whole tuple/map/list, it comes with the upside that dynamic is always explicitly at the root, making it harder to accidentally sneak `dynamic()` in a statically typed program.\n\n## Type inference\n\nType inference (or reconstruction) is the ability of a type system to automatically deduce, either partially or fully, the type of an expression at compile time. Type inference may occur at different levels. For example, many programming languages can automatically infer the types of variables, also known \"local type inference\", but not all can infer type signatures of functions.\n\nInferring type signatures comes with a series of trade-offs:\n\n  * Speed - type inference algorithms are often more computationally intensive than type checking algorithms.\n\n  * Expressiveness - in any given type system, the constructs that support inference are always a subset of those that can be type-checked. Therefore, if a programming language is restricted to fully reconstructed types, it is less expressive than a solely type checked counterpart.\n\n  * Incremental compilation - type inference complicates incremental compilation. If module A depends on module B, which depends on module C, a change to C may require the type signature in B to be reconstructed, which may then require A to be recomputed (and so on). This dependency chain may require large projects to explicitly add type signatures for stability and compilation efficiency.\n\n  * Cascading errors - when a user accidentally makes type errors or the code has conflicting assumptions, type inference may lead to less clear error messages as the type system tries to reconcile diverging type assumptions across code paths.\n\nOn the other hand, type inference offers the benefit of enabling type checking for functions and codebases without requiring the user to add type annotations. To balance these trade-offs, Elixir aims to provide type inference across dependencies: our goal is to infer the types of functions considering the current module, Elixir's standard library and your dependencies, while calls to modules within the same project are assumed to be `dynamic()`. Once types are inferred, then the whole project is type checked considering all modules and all types (inferred or otherwise).\n\nType inference in Elixir is best-effort: it doesn't guarantee it will find all possible type incompatibilities, only that it may find bugs where all combinations of a type _will_ fail, even in the absence of explicit type annotations. It is meant to be an efficient routine that brings developers some benefits of static typing, without requiring any effort from them and keeping the expressiveness of the language.\n\nIn the long term, Elixir developers who want static typing guarantees may explicitly add type signatures to their functions (see \"Roadmap\"). Any function with an explicit type signature will be typed checked against the user-provided annotations, as in other statically typed languages.\n\n### False positives\n\nElixir's type inference generally avoids emitting false positive type violations: which are warnings emitted by the type checker when there are no runtime errors. However, in some situations, those may happen and are documented below.\n\n#### `for`-comprehensions assume they may be executed zero, once, or multiple times\n\nFor comprehensions in Elixir assume they are executed at least once. Take this code:\n\n```elixir\ndef example(x, list) do\n  for _i <- list do\n    Atom.to_string(x)\n  end\n\n  x + 1\nend\n```\n\n`x + 1` will fail because it assumes `x` is an atom from the `Atom.to_string(x)` call, even though the function may raise no runtime error if `list` is an empty list. This is intentional, as it helps find discrepancies inside and outside comprehensions. You can address this by explicitly wrapping the comprehension in a `if list != [] do` block (or similar condition).\n\nSimilar, when using the `:reduce` option, Elixir assumes the list may be empty and therefore the accumulator must match the result type. Take this contrived example:\n\n```elixir\ndef example([_ | _] = list) do\n  Integer.to_string(\n    for i <- list, reduce: :unused do\n      _unused -> i * 2\n    end\n  )\nend\n```\n\nEven though the list is non-empty, for-comprehension always assumes the list can be empty, and the code above will fail because passing `:unused` to `Integer.to_string/1` is a typing violation (which will happen if list is empty). You fix this by making sure the accumulator matches the type of the comprehension body.\n\n#### Struct update syntax must be statically proven\n\nElixir will warn if you use the struct update syntax and it is not statically proven that the given value does not have said struct type. For example:\n\n```elixir\nuser = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\nEven though it is guaranteed at runtime that user is always a `User` struct. If the type system cannot prove it, it will emit a typing violation. This is how struct updates work by design. In such cases, you can address it by matching on the struct when the user variable is defined:\n\n```elixir\n%User{} = user = find_user_by_id(42)\n%User{user | name: \"John Doe\"}\n```\n\n## Roadmap\n\nAt this moment, Elixir implements type inference of all language constructs. The goal is to assess performance and collect feedback on the quality of error messages, before introducing user facing types.\n\nIf the results are satisfactory, the next milestone will include a mechanism for defining typed structs. Elixir programs frequently pattern match on structs, which reveals information about the struct fields, but it knows nothing about their respective types. By propagating types from structs and their fields throughout the program, we will increase the type system’s ability to find errors while further straining our type system implementation. Proposals including the required changes to the language surface will be sent to the community once we reach this stage.\n\nThe third milestone is to introduce set-theoretic type signatures for functions. Unfortunately, the existing Erlang Typespecs are not precise enough for set-theoretic types and they will be phased out of the language and have their postprocessing moved into a separate library once this stage concludes.\n\n## Resources\n\n  * (Paper) [\"The Design Principles of the Elixir Type System\" by Giuseppe Castagna, Guillaume Duboc, José Valim](https://arxiv.org/abs/2306.06391)\n  * (Video) [\"The foundations of the Elixir type system\" by José Valim](https://youtu.be/giYbq4HmfGA)\n  * (Video) [\"Precision in type system design\" by José Valim](https://youtu.be/Ay-gnCqDw9o?t=102)\n\n## Acknowledgements\n\nThe type system was made possible thanks to a partnership between [CNRS](https://www.cnrs.fr/) and [Remote](https://remote.com/). The development work is currently sponsored by [Fresha](https://www.fresha.com/), and [Tidewave](https://tidewave.ai/).\n\n<!-- File: lib/elixir/pages/references/library-guidelines.md (Tokens: ~1598 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Library guidelines\n\nThis document outlines general guidelines for those writing and publishing\nElixir libraries meant to be consumed by other developers.\n\n## Getting started\n\nYou can create a new Elixir library by running the `mix new` command:\n\n    $ mix new my_library\n\nThe project name is given in the `snake_case` convention where all letters are lowercase and words are separate with underscores. This is the same convention used by variables, function names and atoms in Elixir. See the [Naming Conventions](naming-conventions.md) document for more information.\n\nEvery project has a `mix.exs` file, with instructions on how to build, compile, run tests, and so on. Libraries commonly have a `lib` directory, which includes Elixir source code, and a `test` directory. A `src` directory may also exist for Erlang sources.\n\nThe `mix new` command also allows the `--sup` option to scaffold a new project with a supervision tree out of the box. For more information on running your project, see the official [Mix & OTP guide](../mix-and-otp/introduction-to-mix.md) or [Mix documentation](`Mix`).\n\n## Publishing\n\nWriting code is only the first of many steps to publish a package. We strongly recommend developers to:\n\n  * Choose a versioning schema. Elixir requires versions to be in the format `MAJOR.MINOR.PATCH` but the meaning of those numbers is up to you. Most projects choose [Semantic Versioning](https://semver.org/).\n\n  * Choose a [license](https://choosealicense.com/). The most common licenses in the Elixir community are the [MIT License](https://choosealicense.com/licenses/mit/) and the [Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/). The latter is also the one used by Elixir itself.\n\n  * Run the [code formatter](`mix format`). The code formatter formats your code according to a consistent style shared by your library and the whole community, making it easier for other developers to understand your code and contribute.\n\n  * Write tests. Elixir ships with a test-framework named [ExUnit](`ExUnit`). The project generated by `mix new` includes sample tests and doctests.\n\n  * Write documentation. The Elixir community is proud of treating documentation as a first-class citizen and making documentation easily accessible. Libraries contribute to the status quo by providing complete API documentation with examples for their modules, types and functions. See the [Writing documentation](../getting-started/writing-documentation.md) chapter of the Getting Started guide for more information. Projects like [ExDoc](https://github.com/elixir-lang/ex_doc) can be used to generate HTML and EPUB documents from the documentation. ExDoc also supports \"extra pages\", like this one that you are reading. Such pages augment the documentation with tutorials, guides, references, and even cheat-sheets.\n\n  * Follow best practices. The Elixir project documents [a series of anti-patterns](../anti-patterns/what-anti-patterns.md) that you may want to avoid in your code. The [process-related anti-patterns](../anti-patterns/process-anti-patterns.md) and [meta-programming anti-patterns](../anti-patterns/macro-anti-patterns.md) are of special attention to library authors.\n\nProjects are often made available to other developers [by publishing a Hex package](https://hex.pm/docs/publish). Hex also [supports private packages for organizations](https://hex.pm/pricing). If ExDoc is configured for the Mix project, publishing a package on Hex will also automatically publish the generated documentation to [HexDocs](https://hexdocs.pm).\n\n## Dependency handling\n\nWhen your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options.\n\nKeep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI).\n\nOn the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`.\n\nIf you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates.\n\n### Dependency Version Requirements\n\nWhen depending on other libraries, the dependency version requirements are ultimately up to you. However, you should consider the effects that an overly strict dependency requirement can have on users of your library. Most dependencies adopt [Semantic Versioning](https://semver.org/), and therefore provide reasonable guarantees about what each release contains. For instance, if you use `{:some_dep, “== 0.2.3”}`, this prevents users from using any other version but the one that you specified, which means that they cannot receive bug fix upgrades to that package. When in doubt, use a dependency in the format of `\"~> x.y\"`. This prevents the user from using a higher major version of the library, but allows them to upgrade to newer minor and patch versions, which should only include bug fixes and non-breaking improvements.\n\nThe exception to this is pre 1.0 libraries using [Semantic Versioning](https://semver.org/), which provide [no guarantees](https://semver.org/spec/v2.0.0.html#spec-item-4) about what might change from one version to the next. In this scenario, depending on the full patch version, i.e `\"~> 0.1.2\"` is a better default.\n\nA common mistake is to use a dependency in the format of `\"~> x.y.z\"` to express \"a version greater than `x.y.z`\". For example, if you are depending on `\"~> 1.2\"`, and the dependency publishes a fix in version `1.2.1` that you need for the next version of your library. If you use `\"~> 1.2.1\"` to express that dependency, you are preventing users from upgrading to `\"1.3.0\"` or higher! Instead of `\"~> 1.2.1\"`, you should use `\"~> 1.2 and >= 1.2.1\"` as the version requirement. This allows users to use any version less than `2.0`, and greater than `1.2.1`.\n\n<!-- File: lib/elixir/pages/references/naming-conventions.md (Tokens: ~1828 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Naming conventions\n\nThis document is a reference of the naming conventions in Elixir, from casing to punctuation characters.\n\nThe naming convention is, by definition, a subset of the Elixir syntax. A convention aims to\nfollow and set best practices for language and the community. If instead you want a complete reference into the Elixir syntax, beyond its conventions, see [the Syntax reference](syntax-reference.md).\n\n## Casing\n\nElixir developers must use `snake_case` when defining variables, function names, module attributes, and the like:\n\n    some_map = %{this_is_a_key: \"and a value\"}\n    is_map(some_map)\n\nAliases, commonly used as module names, are an exception as they must be capitalized and written in `CamelCase`, like `OptionParser`. For aliases, capital letters are kept in acronyms, like `ExUnit.CaptureIO` or `Mix.SCM`.\n\nAtoms can be written either in `:snake_case` or `:CamelCase`, although the convention is to use the snake case version throughout Elixir.\n\nGenerally speaking, filenames follow the `snake_case` convention of the module they define. For example, `MyApp` should be defined inside the `my_app.ex` file. However, this is only a convention. At the end of the day any filename can be used as they do not affect the compiled code in any way.\n\n## Underscore (`_foo`)\n\nElixir relies on underscores in different situations.\n\nFor example, a value that is not meant to be used must be assigned to `_` or to a variable starting with underscore:\n\n    iex> {:ok, _contents} = File.read(\"README.md\")\n\nFunction names may also start with an underscore. Such functions are never imported by default:\n\n    iex> defmodule Example do\n    ...>   def _wont_be_imported do\n    ...>     :oops\n    ...>   end\n    ...> end\n\n    iex> import Example\n    iex> _wont_be_imported()\n    ** (CompileError) iex:1: undefined function _wont_be_imported/0\n\nDue to this property, Elixir relies on functions starting with underscore to attach compile-time metadata to modules. Such functions are most often in the `__foo__` format. For example, every module in Elixir has an [`__info__/1`](`c:Module.__info__/1`) function:\n\n    iex> String.__info__(:functions)\n    [at: 2, capitalize: 1, chunk: 2, ...]\n\nElixir also includes five special forms that follow the double underscore format: `__CALLER__/0`, `__DIR__/0`, `__ENV__/0`and `__MODULE__/0` retrieve compile-time information about the current environment, while `__STACKTRACE__/0` retrieves the stacktrace for the current exception.\n\n## Trailing bang (`foo!`)\n\nA trailing bang (exclamation mark) signifies a function or macro where failure cases raise an exception. They most often exist as a \"raising variant\" of a function that returns `:ok`/`:error` tuples (or `nil`).\n\nOne example is `File.read/1` and `File.read!/1`. `File.read/1` will return a success or failure tuple, whereas `File.read!/1` will return a plain value or else raise an exception:\n\n    iex> File.read(\"file.txt\")\n    {:ok, \"file contents\"}\n    iex> File.read(\"no_such_file.txt\")\n    {:error, :enoent}\n\n    iex> File.read!(\"file.txt\")\n    \"file contents\"\n    iex> File.read!(\"no_such_file.txt\")\n    ** (File.Error) could not read file no_such_file.txt: no such file or directory\n\nThe version without `!` is preferred when you want to handle different outcomes using pattern matching:\n\n    case File.read(file) do\n      {:ok, body} -> # do something with the `body`\n      {:error, reason} -> # handle the error caused by `reason`\n    end\n\nHowever, if you expect the outcome to always be successful (for instance, if you expect the file always to exist), the bang variation can be more convenient and will raise a more helpful error message (than a failed pattern match) on failure.\n\nWhen thinking about failure cases, we are often thinking about semantic errors related to the operation being performed, such as failing to open a file or trying to fetch key from a map. Errors that come from invalid argument types, or similar, must always raise regardless if the function has a bang or not. In such cases, the exception is often an `ArgumentError` or a detailed `FunctionClauseError`:\n\n    iex(1)> File.read(123)\n    ** (FunctionClauseError) no function clause matching in IO.chardata_to_string/1\n\n        The following arguments were given to IO.chardata_to_string/1:\n\n            # 1\n            123\n\n        Attempted function clauses (showing 2 out of 2):\n\n            def chardata_to_string(string) when is_binary(string)\n            def chardata_to_string(list) when is_list(list)\n\nMore examples of paired functions: `Base.decode16/2` and `Base.decode16!/2`, `File.cwd/0` and `File.cwd!/0`. In some situations, you may have bang functions without a non-bang counterpart. They also imply the possibility of errors, such as: `Protocol.assert_protocol!/1` and `PartitionSupervisor.resize!/2`. This can be useful if you foresee the possibility of adding a non-raising variant in the future.\n\n## Trailing question mark (`foo?`)\n\nFunctions that return a boolean are named with a trailing question mark.\n\nExamples: `Keyword.keyword?/1`, `Mix.debug?/0`, `String.contains?/2`\n\nHowever, functions that return booleans and are valid in guards follow another convention, described next.\n\n## `is_` prefix (`is_foo`)\n\nType checks and other boolean checks that are allowed in guard clauses are named with an `is_` prefix.\n\nExamples: `Integer.is_even/1`, `is_list/1`\n\nThese 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. Type checks that are not valid in guard clauses do not follow this convention, such as `Keyword.keyword?/1`.\n\nA trailing question mark should not be used in combination with the `is_` prefix.\n\n## Special names\n\nSome names have specific meaning in Elixir. We detail those cases below.\n\n### length and size\n\nWhen you see `size` in a function name, it means the operation runs in constant time (also written as \"O(1) time\") because the size is stored alongside the data structure.\n\nExamples: `map_size/1`, `tuple_size/1`\n\nWhen you see `length`, the operation runs in linear time (\"O(n) time\") because the entire data structure has to be traversed.\n\nExamples: `length/1`, `String.length/1`\n\nIn other words, functions using the word \"size\" in its name will take the same amount of time whether the data structure is tiny or huge. Conversely, functions having \"length\" in its name will take more time as the data structure grows in size.\n\n### get, fetch, fetch!\n\nWhen you see the functions `get`, `fetch`, and `fetch!` for key-value data structures, you can expect the following behaviours:\n\n  * `get` returns a default value (which itself defaults to `nil`) if the key is not present, or returns the requested value.\n  * `fetch` returns `:error` if the key is not present, or returns `{:ok, value}` if it is.\n  * `fetch!` *raises* if the key is not present, or returns the requested value.\n\nExamples: `Map.get/2`, `Map.fetch/2`, `Map.fetch!/2`, `Keyword.get/2`, `Keyword.fetch/2`, `Keyword.fetch!/2`\n\n### compare\n\nThe function `compare/2` should return `:lt` if the first term is less than the second, `:eq` if the two\nterms compare as equivalent, or `:gt` if the first term is greater than the second.\n\nExamples: `DateTime.compare/2`\n\nNote that this specific convention is important due to the expectations of `Enum.sort/2`\n\n<!-- File: lib/elixir/pages/references/operators.md (Tokens: ~1818 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Operators reference\n\nThis document is a complete reference of operators in Elixir, how they are parsed, how they can be defined, and how they can be overridden.\n\n## General operators\n\nElixir provides the following built-in operators:\n\n  * [`+`](`+/1`) and [`-`](`-/1`) - unary positive/negative\n  * [`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), and [`/`](`//2`) - basic arithmetic operations\n  * [`++`](`++/2`) and [`--`](`--/2`) - list concatenation and subtraction\n  * [`and`](`and/2`) and [`&&`](`&&/2`) - strict and relaxed boolean \"and\"\n  * [`or`](`or/2`) and [`||`](`||/2`) - strict and relaxed boolean \"or\"\n  * [`not`](`not/1`) and [`!`](`!/1`) - strict and relaxed boolean \"not\"\n  * [`in`](`in/2`) and [`not in`](`in/2`) - membership\n  * [`@`](`@/1`) - module attribute\n  * [`..`](`../0`), [`..`](`../2`), and [`..//`](`..///3`) - range creation\n  * [`<>`](`<>/2`) - binary concatenation\n  * [`|>`](`|>/2`) - pipeline\n  * [`=~`](`=~/2`) - text-based match\n\nMany of those can be used in guards. Consult the [list of allowed guard functions and operators](patterns-and-guards.md#list-of-allowed-functions-and-operators).\n\nAdditionally, there are a few other operators that Elixir parses but doesn't actually use.\nSee [Custom and overridden operators](#custom-and-overridden-operators) below for a list and for guidelines about their use.\n\nSome other operators are special forms and cannot be overridden:\n\n  * [`^`](`^/1`) - pin operator\n  * [`.`](`./2`) - dot operator\n  * [`=`](`=/2`) - match operator\n  * [`&`](`&/1`) - capture operator\n  * [`::`](`::/2`) - type operator\n\nFinally, these operators appear in the precedence table below but are only meaningful within certain constructs:\n\n  * `=>` - see [`%{}`](`%{}/1`)\n  * `when` - see [Guards](patterns-and-guards.md#guards)\n  * `<-` - see [`for`](`for/1`) and [`with`](`with/1`)\n  * `\\\\` - see [Default arguments](`Kernel#def/2-default-arguments`)\n\n## Comparison operators\n\nElixir provides the following built-in comparison operators (all of which can be used in guards):\n\n  * [`==`](`==/2`) - equal to\n  * [`===`](`===/2`) - strictly equal to\n  * [`!=`](`!=/2`) - not equal to\n  * [`!==`](`!==/2`) - strictly not equal to\n  * [`<`](`</2`) - less-than\n  * [`>`](`>/2`) - greater-than\n  * [`<=`](`<=/2`) - less-than or equal to\n  * [`>=`](`>=/2`) - greater-than or equal to\n\nThe only difference between [`==`](`==/2`) and [`===`](`===/2`) is that [`===`](`===/2`) is strict when it comes to comparing integers and floats:\n\n```elixir\niex> 1 == 1.0\ntrue\niex> 1 === 1.0\nfalse\n```\n\n[`!=`](`!=/2`) and [`!==`](`!==/2`) act as the negation of [`==`](`==/2`) and [`===`](`===/2`), respectively.\n\n## Operator precedence and associativity\n\nThe following is a list of all operators that Elixir is capable of parsing, ordered from higher to lower precedence, alongside their associativity:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`@`                                            | Unary\n`.`                                            | Left\n`+` `-` `!` `^` `not`                          | Unary\n`**`                                           | Left\n`*` `/`                                        | Left\n`+` `-`                                        | Left\n`++` `--` `+++` `---` `..` `<>`                | Right\n`//` (valid only inside `..//`)                | Right\n`in` `not in`                                  | Left\n`\\|>` `<<<` `>>>` `<<~` `~>>` `<~` `~>` `<~>`  | Left\n`<` `>` `<=` `>=`                              | Left\n`==` `!=` `=~` `===` `!==`                     | Left\n`&&` `&&&` `and`                               | Left\n`\\|\\|` `\\|\\|\\|` `or`                           | Left\n`=`                                            | Right\n`&`, `...`                                     | Unary\n`\\|`                                           | Right\n`::`                                           | Right\n`when`                                         | Right\n`<-` `\\\\`                                      | Left\n`=>` (valid only inside `%{}`)                 | None\n\nElixir also has two ternary operators:\n\nOperator                                       | Associativity\n---------------------------------------------- | -------------\n`first..last//step`                            | Right\n`%{map \\| key => value, ...}`                  | None\n\n> #### Deprecated operator precedence {: .info}\n>\n> Elixir parses `not left in right` as `not(left in right)` and `!left in right` as `!(left in right)`, which mismatches the precedence table above, but such behaviour is deprecated and emits a warning. Both constructs must be written as `left not in right` instead. In future major versions, the parser will match the table above.\n\n## Custom and overridden operators\n\nElixir is capable of parsing a predefined set of operators. It's not possible to define new operators (as supported by some languages). However, not all operators that Elixir can parse are *used* by Elixir: for example, `+` and `||` are used by Elixir for addition and boolean *or*, but `<~>` is not used (but valid).\n\nTo define an operator, you can use the usual `def*` constructs (`def`, `defp`, `defmacro`, and so on) but with a syntax similar to how the operator is used:\n\n```elixir\ndefmodule MyOperators do\n  # We define ~> to return the maximum of the given two numbers,\n  # and <~ to return the minimum.\n\n  def a ~> b, do: max(a, b)\n  def a <~ b, do: min(a, b)\nend\n```\n\nTo use the newly defined operators, you **have to** import the module that defines them:\n\n```elixir\niex> import MyOperators\niex> 1 ~> 2\n2\niex> 1 <~ 2\n1\n```\n\nThe following is a table of all the operators that Elixir is capable of parsing, but that are not used by default:\n\n  * `|||`\n  * `&&&`\n  * `<<<`\n  * `>>>`\n  * `<<~`\n  * `~>>`\n  * `<~`\n  * `~>`\n  * `<~>`\n  * `+++`\n  * `---`\n  * `...`\n\nThe following operators are used by the `Bitwise` module when imported: [`&&&`](`Bitwise.&&&/2`), [`<<<`](`Bitwise.<<</2`), [`>>>`](`Bitwise.>>>/2`), and [`|||`](`Bitwise.|||/2`). See the `Bitwise` documentation for more information.\n\nNote that the Elixir community generally discourages custom operators. They can be hard to read and even more to understand, as they don't have a descriptive name like functions do. That said, some specific cases or custom domain specific languages (DSLs) may justify these practices.\n\nIt is also possible to replace predefined operators, such as `+`, but doing so is extremely discouraged.\n\n<!-- File: lib/elixir/pages/references/patterns-and-guards.md (Tokens: ~4972 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Patterns and guards\n\nElixir provides pattern matching, which allows us to assert on the shape or extract values from data structures. Patterns are often augmented with guards, which give developers the ability to perform more complex checks, albeit limited.\n\nThis document provides a complete reference on patterns and guards, their semantics, where they are allowed, and how to extend them.\n\n## Patterns\n\nPatterns in Elixir are made of variables, literals, and data structure specific syntax. One of the most used constructs to perform pattern matching is the match operator ([`=`](`=/2`)):\n\n```iex\niex> x = 1\n1\niex> 1 = x\n1\n```\n\nIn the example above, `x` starts without a value and has `1` assigned to it. Then, we compare the value of `x` to the literal `1`, which succeeds as they are both `1`.\n\nMatching `x` against 2 would raise:\n\n```iex\niex> 2 = x\n** (MatchError) no match of right hand side value: 1\n```\n\nPatterns are not bidirectional. If you have a variable `y` that was never assigned to (often called an unbound variable) and you write `1 = y`, an error will be raised:\n\n```iex\niex> 1 = y\n** (CompileError) iex:2: undefined variable \"y\"\n```\n\nIn other words, patterns are allowed only on the left side of `=`. The right side of `=` follows the regular evaluation semantics of the language.\n\nNow let's cover the pattern matching rules for each construct and then for each relevant data types.\n\n### Variables\n\nVariables in patterns are always assigned to:\n\n```iex\niex> x = 1\n1\niex> x = 2\n2\niex> x\n2\n```\n\nIn other words, Elixir supports rebinding. In case you don't want the value of a variable to change, you can use the pin operator (`^`):\n\n```iex\niex> x = 1\n1\niex> ^x = 2\n** (MatchError) no match of right hand side value: 2\n```\n\nIf the same variable appears multiple times in the same pattern, then all of them must be bound to the same value:\n\n```iex\niex> {x, x} = {1, 1}\n{1, 1}\niex> {x, x} = {1, 2}\n** (MatchError) no match of right hand side value: {1, 2}\n```\n\nHowever, a variable cannot be defined through itself in the same pattern. This includes cases where the variable appears on both sides of a nested match operator:\n\n```elixir\n{:ok, x} = {x, :ok}\n%{a: value} = %{b: value}\n```\n\nSuch patterns are rejected as cyclic variable definitions. You can rewrite them by matching once and then using guards or separate comparisons for the additional constraints.\n\nThe underscore variable (`_`) has a special meaning as it can never be bound to any value. It is especially useful when you don't care about certain value in a pattern:\n\n```iex\niex> {_, integer} = {:not_important, 1}\n{:not_important, 1}\niex> integer\n1\niex> _\n** (CompileError) iex:3: invalid use of _\n```\n\nA pinned value represents the value itself and not its – even if syntactically equal – pattern. The right hand side is compared to be equal to the pinned value:\n\n```iex\niex> x = %{}\n%{}\niex> {:ok, %{}} = {:ok, %{a: 13}}\n{:ok, %{a: 13}}\niex> {:ok, ^x} = {:ok, %{a: 13}}\n** (MatchError) no match of right hand side value: {:ok, %{a: 13}}\n    (stdlib 6.2) erl_eval.erl:667: :erl_eval.expr/6\n    iex:2: (file)\n```\n\n### Literals (numbers and atoms)\n\nAtoms and numbers (integers and floats) can appear in patterns and they are always represented as is. For example, an atom will only match an atom if they are the same atom:\n\n```iex\niex> :atom = :atom\n:atom\niex> :atom = :another_atom\n** (MatchError) no match of right hand side value: :another_atom\n```\n\nSimilar rule applies to numbers. Finally, note that numbers in patterns perform strict comparison. In other words, integers to do not match floats:\n\n```iex\niex> 1 = 1.0\n** (MatchError) no match of right hand side value: 1.0\n```\n\n### Tuples\n\nTuples may appear in patterns using the curly brackets syntax (`{}`). A tuple in a pattern will match only tuples of the same size, where each individual tuple element must also match:\n\n```iex\niex> {:ok, integer} = {:ok, 13}\n{:ok, 13}\n\n# won't match due to different size\niex> {:ok, integer} = {:ok, 11, 13}\n** (MatchError) no match of right hand side value: {:ok, 11, 13}\n\n# won't match due to mismatch on first element\niex> {:ok, binary} = {:error, :enoent}\n** (MatchError) no match of right hand side value: {:error, :enoent}\n```\n\n### Lists\n\nLists may appear in patterns using the square brackets syntax (`[]`). A list in a pattern will match only lists of the same size, where each individual list element must also match:\n\n```iex\niex> [:ok, integer] = [:ok, 13]\n[:ok, 13]\n\n# won't match due to different size\niex> [:ok, integer] = [:ok, 11, 13]\n** (MatchError) no match of right hand side value: [:ok, 11, 13]\n\n# won't match due to mismatch on first element\niex> [:ok, binary] = [:error, :enoent]\n** (MatchError) no match of right hand side value: [:error, :enoent]\n```\n\nOpposite to tuples, lists also allow matching on non-empty lists by using the `[head | tail]` notation, which matches on the `head` and `tail` of a list:\n\n```iex\niex> [head | tail] = [1, 2, 3]\n[1, 2, 3]\niex> head\n1\niex> tail\n[2, 3]\n```\n\nMultiple elements may prefix the `| tail` construct:\n\n```iex\niex> [first, second | tail] = [1, 2, 3]\n[1, 2, 3]\niex> tail\n[3]\n```\n\nNote `[head | tail]` does not match empty lists:\n\n```elixir\niex> [head | tail] = []\n** (MatchError) no match of right hand side value: []\n```\n\nGiven charlists are represented as a list of integers, one can also perform prefix matches on charlists using the list concatenation operator ([`++`](`++/2`)):\n\n```elixir\niex> ~c\"hello \" ++ world = ~c\"hello world\"\n~c\"hello world\"\niex> world\n~c\"world\"\n```\n\nWhich is equivalent to matching on `[?h, ?e, ?l, ?l, ?o, ?\\s | world]`. Suffix matches (`hello ++ ~c\" world\"`) are not valid patterns.\n\n### Maps\n\nMaps may appear in patterns using the percentage sign followed by the curly brackets syntax (`%{}`). Opposite to lists and tuples, maps perform a subset match. This means a map pattern will match any other map that has at least all of the keys in the pattern.\n\nHere is an example where all keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\"}\n%{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nHere is when a subset of the keys match:\n\n```iex\niex> %{name: name} = %{name: \"meg\", age: 23}\n%{age: 23, name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf a key in the pattern is not available in the map, then they won't match:\n\n```iex\niex> %{name: name, age: age} = %{name: \"meg\"}\n** (MatchError) no match of right hand side value: %{name: \"meg\"}\n```\n\nNote that the empty map will match all maps, which is a contrast to tuples and lists, where an empty tuple or an empty list will only match empty tuples and empty lists respectively:\n\n```iex\niex> %{} = %{name: \"meg\"}\n%{name: \"meg\"}\n```\n\nFinally, note map keys in patterns must always be literals or previously bound variables matched with the pin operator.\n\n### Structs\n\nStructs may appear in patterns using the percentage sign, the struct module name or a variable followed by the curly brackets syntax (`%{}`).\n\nGiven the following struct:\n\n```elixir\ndefmodule User do\n  defstruct [:name]\nend\n```\n\nHere is an example where all keys match:\n\n```iex\niex> %User{name: name} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> name\n\"meg\"\n```\n\nIf an unknown key is given, the compiler will raise an error:\n\n```iex\niex> %User{type: type} = %User{name: \"meg\"}\n** (CompileError) iex: unknown key :type for struct User\n```\n\nThe struct name can be extracted when putting a variable instead of a module name:\n\n```elixir\niex> %struct_name{} = %User{name: \"meg\"}\n%User{name: \"meg\"}\niex> struct_name\nUser\n```\n\n### Binaries\n\nBinaries may appear in patterns using the double less-than/greater-than syntax ([`<<>>`](`<<>>/1`)). A binary in a pattern can match multiple segments at the same time, each with different type, size, and unit:\n\n```iex\niex> <<val::unit(8)-size(2)-integer>> = <<123, 56>>\n\"{8\"\niex> val\n31544\n```\n\nSee the documentation for [`<<>>`](`<<>>/1`) for a complete definition of pattern matching for binaries.\n\nFinally, remember that strings in Elixir are UTF-8 encoded binaries. This means that, similar to charlists, prefix matches on strings are also possible with the binary concatenation operator ([`<>`](`<>/2`)):\n\n```elixir\niex> \"hello \" <> world = \"hello world\"\n\"hello world\"\niex> world\n\"world\"\n```\n\nSuffix matches (`hello <> \" world\"`) are not valid patterns.\n\n## Guards\n\nGuards are a way to augment pattern matching with more complex checks. They are allowed in a predefined set of constructs where pattern matching is allowed, such as function definitions, case clauses, and others.\n\nNot all expressions are allowed in guard clauses, but only a handful of them. This is a deliberate choice. This way, Elixir (through Erlang) ensures that all guards are predictable (no mutations or other side-effects) and they can be optimized and performed efficiently.\n\n### List of allowed functions and operators\n\nYou can find the built-in list of guards [in the `Kernel` module](`Kernel#guards`). Here is an overview:\n\n  * comparison operators ([`==`](`==/2`), [`!=`](`!=/2`), [`===`](`===/2`), [`!==`](`!==/2`),\n    [`<`](`</2`), [`<=`](`<=/2`), [`>`](`>/2`), [`>=`](`>=/2`)), [`max`](`max/2`), [`min`](`min/2`)\n  * strictly boolean operators ([`and`](`and/2`), [`or`](`or/2`), [`not`](`not/1`)). Note [`&&`](`&&/2`), [`||`](`||/2`), and [`!`](`!/1`) sibling operators are **not allowed** as they're not *strictly* boolean - meaning they don't require arguments to be booleans\n  * arithmetic unary operators ([`+`](`+/1`), [`-`](`-/1`))\n  * arithmetic binary operators ([`+`](`+/2`), [`-`](`-/2`), [`*`](`*/2`), [`/`](`//2`))\n  * [`in`](`in/2`) and [`not in`](`in/2`) operators (as long as the right-hand side is a list or a range)\n  * \"type-check\" functions (`is_list/1`, `is_number/1`, and the like)\n  * functions that work on built-in data types (`abs/1`, `hd/1`, `map_size/1`, and others)\n  * the `map.field` syntax\n\nThe module `Bitwise` also includes a handful of [Erlang bitwise operations as guards](Bitwise.html#guards).\n\nMacros constructed out of any combination of the above guards are also valid guards - for example, `Integer.is_even/1`. For more information, see the \"Custom patterns and guards expressions\" section shown below.\n\n### Why guards\n\nLet's see an example of a guard used in a function clause:\n\n```elixir\ndef empty_map?(map) when map_size(map) == 0, do: true\ndef empty_map?(map) when is_map(map), do: false\n```\n\nGuards start with the `when` operator, followed by a guard expression. The clause will be executed if and only if the guard expression returns `true`. Multiple boolean conditions can be combined with the [`and`](`and/2`) and [`or`](`or/2`) operators.\n\nWriting the `empty_map?/1` function by only using pattern matching would not be possible (as pattern matching on `%{}` would match *any* map, not only the empty ones).\n\n### Non-passing guards\n\nA function clause will be executed if and only if its guard expression evaluates to `true`. If any other value is returned, the function clause will be skipped. In particular, guards have no concept of \"truthy\" or \"falsy\".\n\nFor example, imagine a function that checks that the head of a list is not `nil`:\n\n```elixir\ndef not_nil_head?([head | _]) when head, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> false\n```\n\nEven though the head of the list is not `nil`, the first clause for `not_nil_head?/1` fails because the expression does not evaluate to `true`, but to `\"some_value\"`, therefore triggering the second clause which returns `false`. To make the guard behave correctly, you must ensure that the guard evaluates to `true`, like so:\n\n```elixir\ndef not_nil_head?([head | _]) when head != nil, do: true\ndef not_nil_head?(_), do: false\n\nnot_nil_head?([\"some_value\", \"another_value\"])\n#=> true\n```\n\n### Errors in guards\n\nIn guards, when functions would normally raise exceptions, they cause the guard to fail instead.\n\nFor example, the `tuple_size/1` function only works with tuples. If we use it with anything else, an argument error is raised:\n\n```elixir\niex> tuple_size(\"hello\")\n** (ArgumentError) argument error\n```\n\nHowever, when used in guards, the corresponding clause will fail to match instead of raising an error:\n\n```elixir\niex> case \"hello\" do\n...>   something when tuple_size(something) == 2 ->\n...>     :worked\n...>   _anything_else ->\n...>     :failed\n...> end\n:failed\n```\n\nIn many cases, we can take advantage of this. In the code above, we used `tuple_size/1` to both check that the given value is a tuple *and* check its size (instead of using `is_tuple(something) and tuple_size(something) == 2`).\n\nHowever, if your guard has multiple conditions, such as checking for tuples or maps, it is best to call type-check functions like `is_tuple/1` before `tuple_size/1`, otherwise the whole guard will fail if a tuple is not given. Alternatively, your function clause can use multiple guards as shown in the following section.\n\n### Multiple guards in the same clause\n\nThere exists an additional way to simplify a chain of `or` expressions in guards: Elixir supports writing \"multiple guards\" in the same clause. The following code:\n\n```elixir\ndef categorize_number(term) when is_integer(term) or is_float(term) or is_nil(term),\n  do: :maybe_number\ndef categorize_number(_other),\n  do: :something_else\n```\n\ncan be alternatively written as:\n\n```elixir\ndef categorize_number(term)\n    when is_integer(term)\n    when is_float(term)\n    when is_nil(term) do\n  :maybe_number\nend\n\ndef categorize_number(_other) do\n  :something_else\nend\n```\n\nIf each guard expression always returns a boolean, the two forms are equivalent. However, recall that if any function call in a guard raises an exception, the entire guard fails. To illustrate this, the following function will not detect empty tuples:\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and tuple_size/1 will not be evaluated\n  def empty?(val) when map_size(val) == 0 or tuple_size(val) == 0, do: true\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> false # true was expected!\n```\n\nThis could be corrected by ensuring that no exception is raised, either via type checks like `is_map(val) and map_size(val) == 0`, or by using multiple guards, so that if an exception causes one guard to fail, the next one is evaluated.\n\n```elixir\ndefmodule Check do\n  # If given a tuple, map_size/1 will raise, and the second guard will be evaluated\n  def empty?(val)\n      when map_size(val) == 0\n      when tuple_size(val) == 0,\n      do: true\n\n  def empty?(_val), do: false\nend\n\nCheck.empty?(%{})\n#=> true\n\nCheck.empty?({})\n#=> true\n```\n\n## Where patterns and guards can be used\n\nIn the examples above, we have used the match operator ([`=`](`=/2`)) and function clauses to showcase patterns and guards respectively. Here is the list of the built-in constructs in Elixir that support patterns and guards.\n\n  * `match?/2`:\n\n    ```elixir\n    match?({:ok, value} when value > 0, {:ok, 13})\n    ```\n\n  * function clauses:\n\n    ```elixir\n    def type(term) when is_integer(term), do: :integer\n    def type(term) when is_float(term), do: :float\n    ```\n\n  * [`case`](`case/2`) expressions:\n\n    ```elixir\n    case x do\n      1 -> :one\n      2 -> :two\n      n when is_integer(n) and n > 2 -> :larger_than_two\n    end\n    ```\n\n  * anonymous functions (`fn/1`):\n\n    ```elixir\n    larger_than_two? = fn\n      n when is_integer(n) and n > 2 -> true\n      n when is_integer(n) -> false\n    end\n    ```\n\n  * [`for`](`for/1`) and [`with`](`with/1`) support patterns and guards on the left side of `<-`:\n\n    ```elixir\n    for x when x >= 0 <- [1, -2, 3, -4], do: x\n    ```\n\n    `with` also supports the `else` keyword, which supports patterns matching and guards.\n\n  * [`try`](`try/1`) supports patterns and guards on `catch` and `else`\n\n  * [`receive`](`receive/1`) supports patterns and guards to match on the received messages.\n\n  * custom guards can also be defined with `defguard/1` and `defguardp/1`. A custom guard can only be defined based on existing guards.\n\nNote that the match operator ([`=`](`=/2`)) does *not* support guards:\n\n```elixir\n{:ok, binary} = File.read(\"some/file\")\n```\n\n## Custom patterns and guards expressions\n\nOnly the constructs listed in this page are allowed in patterns and guards. However, we can take advantage of macros to write custom patterns 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 boils down to a combination of the constructs above.\n\nFor example, the `Record` module in Elixir provides a series of macros to be used in patterns and guards that allows tuples to have named fields during compilation.\n\nFor defining your own guards, Elixir even provides conveniences in `defguard` and `defguardp`. Let's look at a quick case study: we want to check whether an argument is an even or an odd integer. With pattern matching this is impossible because there is an infinite number of integers, and therefore we can't pattern match on every single one of them. Therefore we must use guards. We will just focus on checking for even numbers since checking for the odd ones is almost identical.\n\nSuch a guard would look like this:\n\n```elixir\ndef my_function(number) when is_integer(number) and rem(number, 2) == 0 do\n  # do stuff\nend\n```\n\nIt would be repetitive to write every time we need this check. Instead, you can use `defguard/1` and `defguardp/1` to create guard macros. Here's an example how:\n\n```elixir\ndefmodule MyInteger do\n  defguard is_even(term) when is_integer(term) and rem(term, 2) == 0\nend\n```\n\nand then:\n\n```elixir\nimport MyInteger, only: [is_even: 1]\n\ndef my_function(number) when is_even(number) do\n  # do stuff\nend\n```\n\nWhile it's possible to create custom guards with macros, it's recommended to define them using `defguard/1` and `defguardp/1` which perform additional compile-time checks.\n\n<!-- File: lib/elixir/pages/references/sbom.md (Tokens: ~1541 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n-->\n\n# Software Bill of Materials\n\nA Software Bill of Materials (SBoM) is a structured inventory of the components that make up a software system. This guide explains what SBoMs are, why they matter, and how to generate them for Elixir projects.\n\n## What is an SBoM?\n\nAn SBoM is a formal, machine-readable record of all components in a piece of software. Think of it as a detailed ingredient list for your application. A typical SBoM includes:\n\n  * **Dependencies**: all libraries and packages your project uses\n  * **Versions**: the exact version of each component\n  * **Source locations**: where each component was obtained (Hex, GitHub, etc.)\n  * **Checksums**: cryptographic hashes to verify integrity\n  * **Licensing information**: the license under which each component is distributed\n\nTwo widely adopted standards exist for SBoM formats:\n\n  * [CycloneDX](https://cyclonedx.org/): a lightweight standard designed for security contexts\n  * [SPDX](https://spdx.dev/): a more comprehensive standard originally focused on licensing\n\nBoth formats are machine-readable (JSON, XML) and designed to be consumed by automated tooling.\n\n> #### SBoM is an inventory, not a certification {: .info}\n>\n> An SBoM does not claim that software is secure, compliant, or free of vulnerabilities.\n> It simply provides a detailed inventory that enables further analysis. Security and\n> compliance assessments are performed by separate tools that consume the SBoM.\n\n## Why generate SBoMs?\n\nThere are three main reasons to generate SBoMs for your projects.\n\n### Vulnerability analysis\n\nWhen a security vulnerability (CVE) is discovered in a library, you need to quickly determine if your projects are affected. SBoMs make this possible by providing a complete inventory of your dependencies.\n\nTools like [OWASP Dependency-Track](https://dependencytrack.org/) continuously monitor your SBoMs against vulnerability databases. When a new CVE is published, you get notified if any of your projects use the affected component.\n\nWithout an SBoM, answering \"are we affected by CVE-2024-XXXXX?\" means manually checking each project, which is time-consuming and error-prone.\n\n### Regulatory requirements\n\nSBoMs are required by some regulations and procurement policies:\n\n  * **US Executive Order 14028** (2021) requires SBoMs for certain software supplied to the U.S. federal government, particularly for designated critical software\n  * **EU Cyber Resilience Act** introduces requirements for component inventories (commonly fulfilled using SBoMs) for products with digital elements placed on the EU market\n  * **Safety-critical industries** (medical devices, automotive, aerospace) often require detailed component inventories as part of certification\n\nCustomers and partners may also request SBoMs as part of their own compliance efforts.\n\n### License compliance\n\nEvery dependency in your project comes with a license. An SBoM provides a starting point for license review by listing the declared license for each package. This helps you:\n\n  * Get an overview of licenses in your dependency tree\n  * Flag packages that may need closer review\n  * Support due diligence for acquisitions, audits, or legal review\n\nNote that package-level license information (as provided by mix_sbom) reflects what the package declares, not necessarily all licenses present in its source files. For thorough license compliance, file-level scanning tools like ORT provide deeper analysis.\n\n## Generating SBoMs with mix_sbom\n\n[mix_sbom](https://github.com/erlef/mix_sbom) is an EEF project that generates CycloneDX SBoMs for Elixir projects.\n\n### Installation\n\nThere are several ways to install mix_sbom:\n\n  * **As a project dependency**: add `sbom` to your `mix.exs`\n  * **As a global escript**: run `mix escript.install hex sbom` (requires Elixir 1.19.4+)\n  * **As a standalone binary**: download from the [releases page](https://github.com/erlef/mix_sbom/releases)\n\nThe standalone binary is useful for CI environments or when you don't want to modify your project's dependencies. It requires no local Elixir or Erlang installation.\n\n### Basic usage\n\nTo generate an SBoM for your project using the standalone binary:\n\n```console\n$ mix_sbom cyclonedx /path/to/your/project\n```\n\nThis creates a `bom.cdx.json` file in CycloneDX format containing your project's complete dependency tree.\n\n### Common options\n\nThe most useful options are:\n\n  * `-o, --output PATH`: specify the output file (default: `bom.cdx.json`)\n  * `-t, --format FORMAT`: output format (`json`, `xml`, or `protobuf`)\n  * `-s, --schema VERSION`: CycloneDX schema version\n\nFor example, to generate an XML format SBoM:\n\n```console\n$ mix_sbom cyclonedx --format xml --output sbom.xml /path/to/project\n```\n\n## CI integration\n\nFor automated SBoM generation, mix_sbom provides a GitHub Action:\n\n```yaml\nname: Generate SBoM\non:\n  release:\n    types: [published]\n\njobs:\n  sbom:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: erlef/mix_sbom@v0\n        with:\n          path: \".\"\n          format: \"json\"\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sbom\n          path: bom.cdx.json\n```\n\nThis workflow generates an SBoM whenever you publish a release and uploads it as a build artifact. See the [action's documentation](https://github.com/erlef/mix_sbom) for additional options.\n\n## Deeper analysis with ORT\n\nmix_sbom provides package-level license information based on what each dependency declares. However, some compliance workflows require file-level scanning. A package might declare an MIT license but contain individual files under different licenses, or include vendored code with its own licensing terms.\n\nThe [OSS Review Toolkit (ORT)](https://oss-review-toolkit.org/) addresses this by scanning actual source files for license headers and copyright notices. ORT supports Mix projects and provides:\n\n  * **File-level license detection**: scans source code for license texts and SPDX identifiers\n  * **Copyright holder identification**: extracts copyright notices from files\n  * **Policy enforcement**: define rules for allowed and denied licenses\n  * **Multi-ecosystem support**: analyze projects that span multiple package managers\n\nFor organizations with strict compliance requirements, ORT complements mix_sbom by providing the deeper analysis needed for thorough license audits.\n\nSee the [ORT Mix plugin documentation](https://oss-review-toolkit.org/ort/docs/plugins/package-managers/Mix) for details.\n\n## Next steps\n\n  * [CycloneDX Specification](https://cyclonedx.org/specification/overview/): learn more about the SBoM format\n  * [OWASP Dependency-Track](https://dependencytrack.org/): continuous SBoM analysis platform\n  * [mix_sbom documentation](https://sbom.hexdocs.pm): full documentation and advanced options\n\n<!-- File: lib/elixir/pages/references/syntax-reference.md (Tokens: ~4158 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Syntax reference\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). This means the Elixir syntax is mostly uniform with a handful of \"syntax sugar\" constructs to reduce the noise in common Elixir idioms.\n\nThis document covers all of Elixir syntax constructs as a reference and then discuss their exact AST representation.\n\n## Reserved words\n\nThese are the reserved words in the Elixir language. They are detailed throughout this guide but summed up here for convenience:\n\n  * `true`, `false`, `nil` - used as atoms\n  * `when`, `and`, `or`, `not`, `in` - used as operators\n  * `fn` - used for anonymous function definitions\n  * `do`, `end`, `catch`, `rescue`, `after`, `else` - used in do-end blocks\n\n## Data types\n\n### Numbers\n\nIntegers (`1234`) and floats (`123.4`) in Elixir are represented as a sequence of digits that may be separated by underscore for readability purposes, such as `1_000_000`. Integers never contain a dot (`.`) in their representation. Floats contain a dot and at least one other digit after the dot. Floats also support the scientific notation, such as `123.4e10` or `123.4E10`.\n\n### Atoms\n\nUnquoted atoms start with a colon (`:`) which must be immediately followed by a Unicode letter or an underscore. The atom may continue using a sequence of Unicode letters, numbers, underscores, and `@`. Atoms may end in `!` or `?`. Valid unquoted atoms are: `:ok`, `:ISO8601`, and `:integer?`.\n\nIf the colon is immediately followed by a pair of double- or single-quotes surrounding the atom name, the atom is considered quoted. In contrast with an unquoted atom, this one can be made of any Unicode character (not only letters), such as `:'🌢 Elixir'`, `:\"++olá++\"`, and `:\"123\"`.\n\nQuoted and unquoted atoms with the same name are considered equivalent, so `:atom`, `:\"atom\"`, and `:'atom'` represent the same atom. The only catch is that the compiler will warn when quotes are used in atoms that do not need to be quoted.\n\nAll operators in Elixir are also valid atoms. Valid examples are `:foo`, `:FOO`, `:foo_42`, `:foo@bar`, and `:++`. Invalid examples are `:@foo` (`@` is not allowed at start), `:123` (numbers are not allowed at start), and `:(*)` (not a valid operator).\n\n`true`, `false`, and `nil` are reserved words that are represented by the atoms `:true`, `:false` and `:nil` respectively.\n\nTo learn more about all Unicode characters allowed in atom, see the [Unicode syntax](unicode-syntax.md) document.\n\n### Strings\n\nSingle-line strings in Elixir are written between double-quotes, such as `\"foo\"`. Any double-quote inside the string must be escaped with `\\ `. Strings support Unicode characters and are stored as UTF-8 encoded binaries.\n\nMulti-line strings in Elixir are called heredocs. They are written with three double-quotes, and can have unescaped quotes within them. The resulting string will end with a newline. The indentation of the last `\"\"\"` is used to strip indentation from the inner string. For example:\n\n```elixir\niex> test = \"\"\"\n...>     this\n...>     is\n...>     a\n...>     test\n...> \"\"\"\n\"    this\\n    is\\n    a\\n    test\\n\"\niex> test = \"\"\"\n...>     This\n...>     Is\n...>     A\n...>     Test\n...>     \"\"\"\n\"This\\nIs\\nA\\nTest\\n\"\n```\n\nStrings are always represented as themselves in the AST.\n\n### Charlists\n\nCharlists are lists of non-negative integers where each integer represents a Unicode code point.\n\n```elixir\niex(6)> 'abc' === [97, 98, 99]\ntrue\n```\n\nCharlists are written in single-quotes, such as `'foo'`. Any single-quote inside the string must be escaped with `\\ `.\nMulti-line charlists are written with three single-quotes (`'''`), the same way multi-line strings are.\nHowever, this syntax is deprecated in favor of the charlist sigil `~c`.\n\nCharlists are always represented as themselves in the AST.\n\nFor more in-depth information, please read the \"Charlists\" section in the `List` module.\n\n### Lists, tuples and binaries\n\nData structures such as lists, tuples, and binaries are marked respectively by the delimiters `[...]`, `{...}`, and `<<...>>`. Each element is separated by comma. A trailing comma is also allowed, such as in `[1, 2, 3,]`.\n\n### Maps and keyword lists\n\nMaps use the `%{...}` notation and each key-value is given by pairs marked with `=>`, such as `%{\"hello\" => 1, 2 => \"world\"}`.\n\nBoth keyword lists (list of two-element tuples where the first element is an atom) and maps with atom keys support a keyword notation where the colon character `:` is moved to the end of the atom. `%{hello: \"world\"}` is equivalent to `%{:hello => \"world\"}` and `[foo: :bar]` is equivalent to `[{:foo, :bar}]`. We discuss keywords in later sections.\n\n### Structs\n\nStructs built on the map syntax by passing the struct name between `%` and `{`. For example, `%User{...}`.\n\n## Expressions\n\n### Variables\n\nVariables in Elixir must start with an underscore or a Unicode letter that is not in uppercase or titlecase. The variable may continue using a sequence of Unicode letters, numbers, and underscores. Variables may end in `?` or `!`. To learn more about all Unicode characters allowed in variables, see the [Unicode syntax](unicode-syntax.md) document.\n\n[Elixir's naming conventions](naming-conventions.md) recommend variables to be in `snake_case` format.\n\n### Non-qualified calls (local calls)\n\nNon-qualified calls, such as `add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments.\n\nParentheses are required for zero-arity calls (i.e. calls without arguments), to avoid ambiguity with variables. If parentheses are used, they must immediately follow the function name *without spaces*. For example, `add (1, 2)` is a syntax error, since `(1, 2)` is treated as an invalid block which is attempted to be given as a single argument to `add`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Operators\n\nAs many programming languages, Elixir also support operators as non-qualified calls with their precedence and associativity rules. Constructs such as `=`, `when`, `&` and `@` are simply treated as operators. See [the Operators page](operators.md) for a full reference.\n\n### Qualified calls (remote calls)\n\nQualified calls, such as `Math.add(1, 2)`, must start with characters and then follow the same rules as variables, which are optionally followed by parentheses, and then arguments. Qualified calls also support operators, such as `Kernel.+(1, 2)`. Elixir also allows the function name to be written between double- or single-quotes, allowing any character in between the quotes, such as `Math.\"++add++\"(1, 2)`.\n\nSimilar to non-qualified calls, parentheses have different meaning for zero-arity calls (i.e. calls without arguments). If parentheses are used, such as `mod.fun()`, it means a function call. If parenthesis are skipped, such as `map.field`, it means accessing a field of a map.\n\n[Elixir's naming conventions](naming-conventions.md) recommend calls to be in `snake_case` format.\n\n### Aliases\n\nAliases are constructs that expand to atoms at compile-time. The alias `String` expands to the atom `:\"Elixir.String\"`. Aliases must start with an ASCII uppercase character which may be followed by any ASCII letter, number, or underscore. Non-ASCII characters are not supported in aliases.\n\nMultiple aliases can be joined with `.`, such as `MyApp.String`, and it expands to the atom `:\"Elixir.MyApp.String\"`. The dot is effectively part of the name but it can also be used for composition. If you define `alias MyApp.Example, as: Example` in your code, then `Example` will always expand to `:\"Elixir.MyApp.Example\"` and `Example.String` will expand to `:\"Elixir.MyApp.Example.String\"`.\n\n[Elixir's naming conventions](naming-conventions.md) recommend aliases to be in `CamelCase` format.\n\n### Module attributes\n\nModule attributes are module-specific storage and are written as the composition of the unary operator `@` with variables and local calls. For example, to write to a module attribute named `foo`, use `@foo \"value\"`, and use `@foo` to read from it. Given module attributes are written using existing constructs, they follow the same rules above defined for operators, variables, and local calls.\n\n### Blocks\n\nBlocks are multiple Elixir expressions separated by newlines or semi-colons. A new block may be created at any moment by using parentheses.\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is used to establish a relationship between left and right, commonly referred as clauses. The left side may have zero, one, or more arguments; the right side is zero, one, or more expressions separated by new line. The `->` may appear one or more times between one of the following terminators: `do`-`end`, `fn`-`end` or `(`-`)`. When `->` is used, only other clauses are allowed between those terminators. Mixing clauses and regular expressions is invalid syntax.\n\nIt is seen on `case` and `cond` constructs between `do` and `end`:\n\n```elixir\ncase 1 do\n  2 -> 3\n  4 -> 5\nend\n\ncond do\n  true -> false\nend\n```\n\nSeen in typespecs between `(` and `)`:\n\n```elixir\n(integer(), boolean() -> integer())\n```\n\nIt is also used between `fn` and `end` for building anonymous functions:\n\n```elixir\nfn\n  x, y -> x + y\nend\n```\n\n### Sigils\n\nSigils start with `~` and are followed by one lowercase letter or by one or more uppercase letters, immediately followed by one of the following pairs:\n\n  * `(` and `)`\n  * `{` and `}`\n  * `[` and `]`\n  * `<` and `>`\n  * `\"` and `\"`\n  * `'` and `'`\n  * `|` and `|`\n  * `/` and `/`\n\nAfter closing the pair, zero or more ASCII letters and digits can be given as a modifier. Sigils are expressed as non-qualified calls prefixed with `sigil_` where the first argument is the sigil contents as a string and the second argument is a list of integers as modifiers:\n\nIf the sigil letter is in uppercase, no interpolation is allowed in the sigil, otherwise its contents may be dynamic. Compare the results of the sigils below for more information:\n\n```elixir\n~s/f#{\"o\"}o/\n~S/f#{\"o\"}o/\n```\n\nSigils are useful to encode text with their own escaping rules, such as regular expressions, datetimes, and others.\n\n## The Elixir AST\n\nElixir syntax was designed to have a straightforward conversion to an abstract syntax tree (AST). Elixir's AST is a regular Elixir data structure composed of the following elements:\n\n  * atoms - such as `:foo`\n  * integers - such as `42`\n  * floats - such as `13.1`\n  * strings - such as `\"hello\"`\n  * lists - such as `[1, 2, 3]`\n  * tuples with two elements - such as `{\"hello\", :world}`\n  * tuples with three elements, representing calls or variables, as explained next\n\nThe building block of Elixir's AST is a call, such as:\n\n```elixir\nsum(1, 2, 3)\n```\n\nwhich is represented as a tuple with three elements:\n\n```elixir\n{:sum, meta, [1, 2, 3]}\n```\n\nthe first element is an atom (or another tuple), the second element is a list of two-element tuples with metadata (such as line numbers) and the third is a list of arguments.\n\nWe can retrieve the AST for any Elixir expression by calling `quote`:\n\n```elixir\nquote do\n  sum()\nend\n#=> {:sum, [], []}\n```\n\nVariables are also represented using a tuple with three elements and a combination of lists and atoms, for example:\n\n```elixir\nquote do\n  sum\nend\n#=> {:sum, [], Elixir}\n```\n\nYou can see that variables are also represented with a tuple, except the third element is an atom expressing the variable context.\n\nOver the course of this section, we will explore many Elixir syntax constructs alongside their AST representations.\n\n### Operators\n\nOperators are treated as non-qualified calls:\n\n```elixir\nquote do\n  1 + 2\nend\n#=> {:+, [], [1, 2]}\n```\n\nNote that `.` is also an operator. Remote calls use the dot in the AST with two arguments, where the second argument is always an atom:\n\n```elixir\nquote do\n  foo.bar(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}, :bar]}, [], [1, 2, 3]}\n```\n\nCalling anonymous functions uses the dot in the AST with a single argument, mirroring the fact the function name is \"missing\" from right side of the dot:\n\n```elixir\nquote do\n  foo.(1, 2, 3)\nend\n#=> {{:., [], [{:foo, [], Elixir}]}, [], [1, 2, 3]}\n```\n\n### Aliases\n\nAliases are represented by an `__aliases__` call with each segment separated by a dot as an argument:\n\n```elixir\nquote do\n  Foo.Bar.Baz\nend\n#=> {:__aliases__, [], [:Foo, :Bar, :Baz]}\n\nquote do\n  __MODULE__.Bar.Baz\nend\n#=> {:__aliases__, [], [{:__MODULE__, [], Elixir}, :Bar, :Baz]}\n```\n\nAll arguments, except the first, are guaranteed to be atoms.\n\n### Data structures\n\nRemember that lists are literals, so they are represented as themselves in the AST:\n\n```elixir\nquote do\n  [1, 2, 3]\nend\n#=> [1, 2, 3]\n```\n\nTuples have their own representation, except for two-element tuples, which are represented as themselves:\n\n```elixir\nquote do\n  {1, 2}\nend\n#=> {1, 2}\n\nquote do\n  {1, 2, 3}\nend\n#=> {:{}, [], [1, 2, 3]}\n```\n\nBinaries have a representation similar to tuples, except they are tagged with `:<<>>` instead of `:{}`:\n\n```elixir\nquote do\n  <<1, 2, 3>>\nend\n#=> {:<<>>, [], [1, 2, 3]}\n```\n\nThe same applies to maps, where pairs are treated as a list of tuples with two elements:\n\n```elixir\nquote do\n  %{1 => 2, 3 => 4}\nend\n#=> {:%{}, [], [{1, 2}, {3, 4}]}\n```\n\n### Blocks\n\nBlocks are represented as a `__block__` call with each line as a separate argument:\n\n```elixir\nquote do\n  1\n  2\n  3\nend\n#=> {:__block__, [], [1, 2, 3]}\n\nquote do 1; 2; 3; end\n#=> {:__block__, [], [1, 2, 3]}\n```\n\n### Left to right arrow\n\nThe left to right arrow (`->`) is represented similar to operators except that they are always part of a list, its left side represents a list of arguments and the right side is an expression.\n\nFor example, in `case` and `cond`:\n\n```elixir\nquote do\n  case 1 do\n    2 -> 3\n    4 -> 5\n  end\nend\n#=> {:case, [], [1, [do: [{:->, [], [[2], 3]}, {:->, [], [[4], 5]}]]]}\n\nquote do\n  cond do\n    true -> false\n  end\nend\n#=> {:cond, [], [[do: [{:->, [], [[true], false]}]]]}\n```\n\nBetween `(` and `)`:\n\n```elixir\nquote do\n  (1, 2 -> 3\n   4, 5 -> 6)\nend\n#=> [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]\n```\n\nBetween `fn` and `end`:\n\n```elixir\nquote do\n  fn\n    1, 2 -> 3\n    4, 5 -> 6\n  end\nend\n#=> {:fn, [], [{:->, [], [[1, 2], 3]}, {:->, [], [[4, 5], 6]}]}\n```\n\n### Qualified tuples\n\nQualified tuples (`foo.{bar, baz}`) are represented by a `{:., [], [expr, :{}]}` call, where the `expr` represents the left hand side of the dot, and the arguments represent the elements inside the curly braces. This is used in Elixir to provide multi aliases:\n\n```elixir\nquote do\n  Foo.{Bar, Baz}\nend\n#=> {{:., [], [{:__aliases__, [], [:Foo]}, :{}]}, [], [{:__aliases__, [], [:Bar]}, {:__aliases__, [], [:Baz]}]}\n```\n\n### `do`-`end` blocks\n\nElixir's `do`-`end` blocks are equivalent to keywords as the last argument of a function call, where the block contents are wrapped in parentheses. For example:\n\n```elixir\nif true do\n  this\nelse\n  that\nend\n```\n\nis the same as:\n\n```elixir\nif(true, do: (this), else: (that))\n```\n\nWhile the construct above does not require custom nodes in Elixir's AST, they are restricted only to certain keywords, listed next:\n\n  * `after`\n  * `catch`\n  * `else`\n  * `rescue`\n\nYou will find them in constructs such as `receive`, `try`, and others. You can also find more examples in [the Optional Syntax chapter](../getting-started/optional-syntax.md).\n\n<!-- File: lib/elixir/pages/references/typespecs.md (Tokens: ~4855 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Typespecs reference\n\n> #### Typespecs are not set-theoretic types {: .warning}\n>\n> Elixir is in the process of implementing its\n> [own type system](./gradual-set-theoretic-types.md) based on set-theoretic types.\n> Typespecs, which are described in the following document, are a distinct notation\n> for declaring types and specifications based on Erlang.\n> Typespecs may be phased out as the set-theoretic type effort moves forward.\n\nElixir is a dynamically typed language, and as such, type specifications are never used by the compiler to optimize or modify code. Still, using type specifications is useful because:\n\n  * they provide documentation (for example, tools such as [`ExDoc`](https://ex-doc.hexdocs.pm/) show type specifications in the documentation)\n  * they're used by tools such as [Dialyzer](`:dialyzer`), that can analyze code with typespecs to find type inconsistencies and possible bugs\n\nType specifications (most often referred to as *typespecs*) are defined in different contexts using the following attributes:\n\n  * `@type`\n  * `@opaque`\n  * `@typep`\n  * `@spec`\n  * `@callback`\n  * `@macrocallback`\n\nIn addition, you can use `@typedoc` to document a custom `@type` definition.\n\nSee the \"User-defined types\" and \"Defining a specification\" sub-sections below for more information on defining types and typespecs.\n\n## A simple example\n\n    defmodule StringHelpers do\n      @typedoc \"A word from the dictionary\"\n      @type word() :: String.t()\n\n      @spec long_word?(word()) :: boolean()\n      def long_word?(word) when is_binary(word) do\n        String.length(word) > 8\n      end\n    end\n\nIn the example above:\n\n  * We declare a new type (`word()`) that is equivalent to the string type (`String.t()`).\n\n  * We describe the type using a `@typedoc`, which will be included in the generated documentation.\n\n  * We specify that the `long_word?/1` function takes an argument of type `word()` and\n    returns a boolean (`boolean()`), that is, either `true` or `false`.\n\n## Types and their syntax\n\nThe syntax Elixir provides for type specifications is similar to [the one in Erlang](https://www.erlang.org/doc/reference_manual/typespec.html). Most of the built-in types provided in Erlang (for example, `pid()`) are expressed in the same way: `pid()` (or simply `pid`). Parameterized types (such as `list(integer)`) are supported as well and so are remote types (such as [`Enum.t()`](`t:Enum.t/0`)). Integers and atom literals are allowed as types (for example, `1`, `:atom`, or `false`). All other types are built out of unions of predefined types. Some types can also be declared using their syntactical notation, such as `[type]` for lists, `{type1, type2, ...}` for tuples and `<<_ * _>>` for binaries.\n\nThe notation to represent the union of types is the pipe `|`. For example, the typespec `type :: atom() | pid() | tuple()` creates a type `type` that can be either an `atom`, a `pid`, or a `tuple`. This is usually called a [sum type](https://en.wikipedia.org/wiki/Tagged_union) in other languages\n\n> #### Differences with set-theoretic types {: .warning}\n>\n> While they do share some similarities, the types below do not map one-to-one\n> to the new types from the set-theoretic type system.\n>\n> For example, there is no plan to support subsets of the `integer()` type such\n> as positive, ranges or literals.\n>\n> Furthermore, set-theoretic types support the full range of set operations,\n> including intersections and negations.\n\n### Basic types\n\n    type ::\n          any()                     # the top type, the set of all terms\n          | none()                  # the bottom type, contains no terms\n          | atom()\n          | map()                   # any map\n          | pid()                   # process identifier\n          | port()                  # port identifier\n          | reference()\n          | tuple()                 # tuple of any size\n\n                                    ## Numbers\n          | float()\n          | integer()\n          | neg_integer()           # ..., -3, -2, -1\n          | non_neg_integer()       # 0, 1, 2, 3, ...\n          | pos_integer()           # 1, 2, 3, ...\n\n                                                                          ## Lists\n          | list(type)                                                    # proper list ([]-terminated)\n          | nonempty_list(type)                                           # non-empty proper list\n          | maybe_improper_list(content_type, termination_type)           # proper or improper list\n          | nonempty_improper_list(content_type, termination_type)        # improper list\n          | nonempty_maybe_improper_list(content_type, termination_type)  # non-empty proper or improper list\n\n          | Literals                # Described in section \"Literals\"\n          | BuiltIn                 # Described in section \"Built-in types\"\n          | Remotes                 # Described in section \"Remote types\"\n          | UserDefined             # Described in section \"User-defined types\"\n\n### Literals\n\nThe following literals are also supported in typespecs:\n\n    type ::                               ## Atoms\n          :atom                           # atoms: :foo, :bar, ...\n          | true | false | nil            # special atom literals\n\n                                          ## Bitstrings\n          | <<>>                          # empty bitstring\n          | <<_::size>>                   # size is 0 or a positive integer\n          | <<_::_*unit>>                 # unit is an integer from 1 to 256\n          | <<_::size, _::_*unit>>\n\n                                          ## (Anonymous) Functions\n          | (-> type)                     # zero-arity, returns type\n          | (type1, type2 -> type)        # two-arity, returns type\n          | (... -> type)                 # any arity, returns type\n\n                                          ## Integers\n          | 1                             # integer\n          | 1..10                         # integer from 1 to 10\n\n                                          ## Lists\n          | [type]                        # list with any number of type elements\n          | []                            # empty list\n          | [...]                         # shorthand for nonempty_list(any())\n          | [type, ...]                   # shorthand for nonempty_list(type)\n          | [key: value_type]             # keyword list with optional key :key of value_type\n\n                                                  ## Maps\n          | %{}                                   # empty map\n          | %{key: value_type}                    # map with required key :key of value_type\n          | %{key_type => value_type}             # map with required pairs of key_type and value_type\n          | %{required(key_type) => value_type}   # map with required pairs of key_type and value_type\n          | %{optional(key_type) => value_type}   # map with optional pairs of key_type and value_type\n          | %SomeStruct{}                         # struct with all fields of any type\n          | %SomeStruct{key: value_type}          # struct with required key :key of value_type\n\n                                          ## Tuples\n          | {}                            # empty tuple\n          | {:ok, type}                   # two-element tuple with an atom and any type\n\n### Built-in types\n\nThe following types are also provided by Elixir as shortcuts on top of the basic and literal types described above.\n\nBuilt-in type           | Defined as\n:---------------------- | :---------\n`term()`                | `any()`\n`arity()`               | `0..255`\n`as_boolean(t)`         | `t`\n`binary()`              | `<<_::_*8>>`\n`nonempty_binary()`     | `<<_::8, _::_*8>>`\n`bitstring()`           | `<<_::_*1>>`\n`nonempty_bitstring()`  | `<<_::1, _::_*1>>`\n`boolean()`             | `true` \\| `false`\n`byte()`                | `0..255`\n`char()`                | `0..0x10FFFF`\n`charlist()`            | `[char()]`\n`nonempty_charlist()`   | `[char(), ...]`\n`fun()`                 | `(... -> any)`\n`function()`            | `fun()`\n`identifier()`          | `pid()` \\| `port()` \\| `reference()`\n`iodata()`              | `iolist()` \\| `binary()`\n`iolist()`              | `maybe_improper_list(byte() \\| binary() \\| iolist(), binary() \\| [])`\n`keyword()`             | `[{atom(), any()}]`\n`keyword(t)`            | `[{atom(), t}]`\n`list()`                | `[any()]`\n`nonempty_list()`       | `nonempty_list(any())`\n`maybe_improper_list()` | `maybe_improper_list(any(), any())`\n`nonempty_maybe_improper_list()` | `nonempty_maybe_improper_list(any(), any())`\n`mfa()`                 | `{module(), atom(), arity()}`\n`module()`              | `atom()`\n`no_return()`           | `none()`\n`node()`                | `atom()`\n`number()`              | `integer()` \\| `float()`\n`struct()`              | `%{:__struct__ => atom(), optional(atom()) => any()}`\n`timeout()`             | `:infinity` \\| `non_neg_integer()`\n\n`as_boolean(t)` exists to signal users that the given value will be treated as a boolean, where `nil` and `false` will be evaluated as `false` and everything else is `true`. For example, `Enum.filter/2` has the following specification: `filter(t, (element -> as_boolean(term))) :: list`.\n\n### Remote types\n\nAny module is also able to define its own types and the modules in Elixir are no exception. For example, the `Range` module defines a `t/0` type that represents a range: this type can be referred to as `t:Range.t/0`. In a similar fashion, a string is `t:String.t/0`, and so on.\n\n### Maps\n\nThe key types in maps are allowed to overlap, and if they do, the leftmost key takes precedence.\nA map value does not belong to this type if it contains a key that is not in the allowed map keys.\n\nIf you want to denote that keys that were not previously defined in the map are allowed,\nit is common to end a map type with `optional(any) => any`.\n\nNote that the syntactic representation of `map()` is `%{optional(any) => any}`, not `%{}`. The notation `%{}` specifies the singleton type for the empty map.\n\n### Keyword Lists\n\nBeyond `keyword()` and `keyword(t)`, it can be helpful to compose a spec for an expected keyword list.\nFor example:\n\n```elixir\n@type option :: {:name, String.t} | {:max, pos_integer} | {:min, pos_integer}\n@type options :: [option()]\n```\n\nThis makes it clear that only these options are allowed, none are required, and order does not matter.\n\nIt also allows composition with existing types.\nFor example:\n\n```elixir\n@type option :: {:my_option, String.t()} | GenServer.option()\n\n@spec start_link([option()]) :: GenServer.on_start()\ndef start_link(opts) do\n  {my_opts, gen_server_opts} = Keyword.split(opts, [:my_option])\n  GenServer.start_link(__MODULE__, my_opts, gen_server_opts)\nend\n```\n\nThe following spec syntaxes are equivalent:\n\n```elixir\n@type options :: [{:name, String.t} | {:max, pos_integer} | {:min, pos_integer}]\n\n@type options :: [name: String.t, max: pos_integer, min: pos_integer]\n```\n\n### User-defined types\n\nThe `@type`, `@typep`, and `@opaque` module attributes can be used to define new types:\n\n    @type type_name :: type\n    @typep type_name :: type\n    @opaque type_name :: type\n\nA type defined with `@typep` is private. An opaque type, defined with `@opaque` is a type where the internal structure of the type will not be visible, but the type is still public.\n\nTypes can be parameterized by defining variables as parameters; these variables can then be used to define the type.\n\n    @type dict(key, value) :: [{key, value}]\n\n## Defining a specification\n\nA specification for a function can be defined as follows:\n\n    @spec function_name(type1, type2) :: return_type\n\nGuards can be used to restrict type variables given as arguments to the function.\n\n    @spec function(arg) :: [arg] when arg: atom\n\nIf you want to specify more than one variable, you separate them by a comma.\n\n    @spec function(arg1, arg2) :: {arg1, arg2} when arg1: atom, arg2: integer\n\nType variables with no restriction can also be defined using `var`.\n\n    @spec function(arg) :: [arg] when arg: var\n\nThis guard notation only works with `@spec`, `@callback`, and `@macrocallback`.\n\nYou can also name your arguments in a typespec using `arg_name :: arg_type` syntax. This is particularly useful in documentation as a way to differentiate multiple arguments of the same type (or multiple elements of the same type in a type definition):\n\n    @spec days_since_epoch(year :: integer, month :: integer, day :: integer) :: integer\n    @type color :: {red :: integer, green :: integer, blue :: integer}\n\nSpecifications can be overloaded, just like ordinary functions.\n\n    @spec function(integer) :: atom\n    @spec function(atom) :: integer\n\n## Behaviours\n\nBehaviours in Elixir (and Erlang) are a way to separate and abstract the generic part of a component (which becomes the *behaviour module*) from the specific part (which becomes the *callback module*).\n\nA behaviour module defines a set of functions and macros (referred to as *callbacks*) that callback modules implementing that behaviour must export. This \"interface\" identifies the specific part of the component. For example, the `GenServer` behaviour and functions abstract away all the message-passing (sending and receiving) and error reporting that a \"server\" process will likely want to implement from the specific parts such as the actions that this server process has to perform.\n\nSay we want to implement a bunch of parsers, each parsing structured data: for example, a JSON parser and a MessagePack parser. Each of these two parsers will *behave* the same way: both will provide a `parse/1` function and an `extensions/0` function. The `parse/1` function will return an Elixir representation of the structured data, while the `extensions/0` function will return a list of file extensions that can be used for each type of data (e.g., `.json` for JSON files).\n\nWe can create a `Parser` behaviour:\n\n```elixir\ndefmodule Parser do\n  @doc \"\"\"\n  Parses a string.\n  \"\"\"\n  @callback parse(String.t) :: {:ok, term} | {:error, atom}\n\n  @doc \"\"\"\n  Lists all supported file extensions.\n  \"\"\"\n  @callback extensions() :: [String.t]\nend\n```\n\nAs seen in the example above, defining a callback is a matter of defining a specification for that callback, made of:\n\n  * the callback name (`parse` or `extensions` in the example)\n  * the arguments that the callback must accept (`String.t`)\n  * the *expected* type of the callback return value\n\nModules adopting the `Parser` behaviour will have to implement all the functions defined with the `@callback` attribute. As you can see, `@callback` expects a function name but also a function specification like the ones used with the `@spec` attribute we saw above.\n\n### Implementing behaviours\n\nImplementing a behaviour is straightforward:\n\n```elixir\ndefmodule JSONParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some json \" <> str} # ... parse JSON\n\n  @impl Parser\n  def extensions, do: [\".json\"]\nend\n```\n\n```elixir\ndefmodule CSVParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse(str), do: {:ok, \"some csv \" <> str} # ... parse CSV\n\n  @impl Parser\n  def extensions, do: [\".csv\"]\nend\n```\n\nIf a module adopting a given behaviour doesn't implement one of the callbacks required by that behaviour, a compile-time warning will be generated.\n\nFurthermore, with `@impl` you can also make sure that you are implementing the **correct** callbacks from the given behaviour in an explicit manner. For example, the following parser implements both `parse` and `extensions`. However, thanks to a typo, `BADParser` is implementing `parse/0` instead of `parse/1`.\n\n```elixir\ndefmodule BADParser do\n  @behaviour Parser\n\n  @impl Parser\n  def parse, do: {:ok, \"something bad\"}\n\n  @impl Parser\n  def extensions, do: [\"bad\"]\nend\n```\n\nThis code generates a warning letting you know that you are mistakenly implementing `parse/0` instead of `parse/1`.\nYou can read more about `@impl` in the [module documentation](`Module#module-impl`).\n\n### Using behaviours\n\nBehaviours are useful because you can pass modules around as arguments and you can then *call back* to any of the functions specified in the behaviour. For example, we can have a function that receives a filename, several parsers, and parses the file based on its extension:\n\n```elixir\n@spec parse_path(Path.t(), [module()]) :: {:ok, term} | {:error, atom}\ndef parse_path(filename, parsers) do\n  with {:ok, ext} <- parse_extension(filename),\n       {:ok, parser} <- find_parser(ext, parsers),\n       {:ok, contents} <- File.read(filename) do\n    parser.parse(contents)\n  end\nend\n\ndefp parse_extension(filename) do\n  case Path.extname(filename) do\n    \"\" -> {:error, :no_extension}\n    ext -> {:ok, ext}\n  end\nend\n\ndefp find_parser(ext, parsers) do\n  if parser = Enum.find(parsers, fn parser -> ext in parser.extensions() end) do\n    {:ok, parser}\n  else\n    {:error, :no_matching_parser}\n  end\nend\n```\n\nYou could also invoke any parser directly: `CSVParser.parse(...)`.\n\nNote you don't need to define a behaviour in order to dynamically dispatch on a module, but those features often go hand in hand.\n\n### Optional callbacks\n\nOptional callbacks are callbacks that callback modules may implement if they want to, but are not required to. Usually, behaviour modules know if they should call those callbacks based on configuration, or they check if the callbacks are defined with `function_exported?/3` or `macro_exported?/3`.\n\n> ### Unloaded modules {: .warning}\n>\n> `function_exported?/3` (and `macro_exported?/3`) do *not* load the module in case it is not loaded and Elixir lazily loads modules by default (except on releases). So in practice you will want to invoke `Code.ensure_loaded?/1` before checking if the function/macro is exported. See the documentation for `function_exported?/3` for examples.\n\nOptional callbacks can be defined through the `@optional_callbacks` module attribute, which has to be a keyword list with function or macro name as key and arity as value. For example:\n\n    defmodule MyBehaviour do\n      @callback vital_fun() :: any\n      @callback non_vital_fun() :: any\n      @macrocallback non_vital_macro(arg :: any) :: Macro.t\n      @optional_callbacks non_vital_fun: 0, non_vital_macro: 1\n    end\n\nOne example of optional callback in Elixir's standard library is `c:GenServer.format_status/1`.\n\n### Inspecting behaviours\n\nThe `@callback` and `@optional_callbacks` attributes are used to create a `behaviour_info/1` function available on the defining module. This function can be used to retrieve the callbacks and optional callbacks defined by that module.\n\nFor example, for the `MyBehaviour` module defined in \"Optional callbacks\" above:\n\n    MyBehaviour.behaviour_info(:callbacks)\n    #=> [vital_fun: 0, \"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n    MyBehaviour.behaviour_info(:optional_callbacks)\n    #=> [\"MACRO-non_vital_macro\": 2, non_vital_fun: 0]\n\nWhen using `iex`, the `IEx.Helpers.b/1` helper is also available.\n\n## Pitfalls\n\nThere are some known pitfalls when using typespecs, they are documented next.\n\n## The `string()` type\n\nElixir discourages the use of the `string()` type. The `string()` type refers to Erlang strings, which are known as \"charlists\" in Elixir. They do not refer to Elixir strings, which are UTF-8 encoded binaries. To avoid confusion, if you attempt to use the type `string()`, Elixir will emit a warning. You should use `charlist()`, `nonempty_charlist()`, `binary()` or `String.t()` accordingly, or any of the several literal representations for these types.\n\nNote that `String.t()` and `binary()` are equivalent to analysis tools. Although, for those reading the documentation, `String.t()` implies it is a UTF-8 encoded binary.\n\n## Functions which raise an error\n\nTypespecs do not need to indicate that a function can raise an error; any function can fail any time if given invalid input.\nIn the past, the Elixir standard library sometimes used `no_return()` to indicate this, but these usages have been removed.\n\nThe `no_return()` type also should not be used for functions which do return but whose purpose is a \"side effect\", such as `IO.puts/1`.\nIn these cases, the expected return type is `:ok`.\n\nInstead, `no_return()` should be used as the return type for functions which can never return a value.\nThis includes functions which loop forever calling `receive`, or which exist specifically to raise an error, or which shut down the VM.\n\n<!-- File: lib/elixir/pages/references/unicode-syntax.md (Tokens: ~2585 | Category: anthropic-skill) -->\n<!--\n  SPDX-License-Identifier: Apache-2.0\n  SPDX-FileCopyrightText: 2021 The Elixir Team\n  SPDX-FileCopyrightText: 2012 Plataformatec\n-->\n\n# Unicode syntax\n\nElixir supports Unicode throughout the language. This document is a complete reference of how\nElixir supports Unicode in its syntax.\n\nStrings (`\"olá\"`) and charlists (`'olá'`) support Unicode since Elixir v1.0. Strings are UTF-8 encoded. Charlists are lists of Unicode code points. In such cases, the contents are kept as written by developers, without any transformation.\n\nElixir also supports Unicode in variables, atoms, and calls since Elixir v1.5. The focus of this document is to provide a high-level introduction to how Elixir allows Unicode in its syntax. We also provide technical documentation describing how Elixir complies with the Unicode specification.\n\nTo check the Unicode version of your current Elixir installation, run `String.Unicode.version()`.\n\n## Introduction\n\nElixir allows Unicode characters in its variables, atoms, and calls. However, the Unicode characters must still obey the rules of the language syntax. In particular, variables and calls cannot start with an uppercase letter. From now on, we will refer to those terms as identifiers.\n\nThe characters allowed in identifiers are the ones specified by Unicode. Generally speaking, it is restricted to characters typically used by the writing system of human languages still in activity. In particular, it excludes symbols such as emojis, alternate numeric representations, musical notes, and the like.\n\nElixir imposes many restrictions on identifiers for security purposes. For example, the word \"josé\" can be written in two ways in Unicode: as the combination of the characters `j o s é` and as a combination of the characters `j o s e ́ `, where the accent is its own character. The former is called NFC form and the latter is the NFD form. Elixir normalizes all characters to be the in the NFC form.\n\nElixir also disallows mixed-scripts which are not explicitly separated by `_`. For example, it is not possible to name a variable `аdmin`, where `а` is in Cyrillic and the remaining characters are in Latin. Doing so will raise the following error:\n\n```text\n** (SyntaxError) invalid mixed-script identifier found: аdmin\n\nMixed-script identifiers are not supported for security reasons. 'аdmin' is made of the following scripts:\n\n  \\u0430 а {Cyrillic}\n  \\u0064 d {Latin}\n  \\u006D m {Latin}\n  \\u0069 i {Latin}\n  \\u006E n {Latin}\n\nMake sure all characters in the identifier resolve to a single script or a highly\nrestrictive script. See https://elixir.hexdocs.pm/unicode-syntax.html for more information.\n```\n\nFinally, Elixir will also warn of confusable identifiers in the same file. For example, Elixir will emit a warning if you use both variables `а` (Cyrillic) and `а` (Latin) in your code.\n\nThat's the overall introduction of how Unicode is used in Elixir identifiers. In a nutshell, its goal is to support different writing systems in use today while keeping the Elixir language itself clear and secure.\n\nFor the technical details, see the next sections that cover the technical Unicode requirements.\n\n## Unicode Standard Annex #31\n\nElixir conforms to the standards outlined in the [Unicode Standard Annex #31: Unicode Identifiers and Syntax](https://unicode.org/reports/tr31/), version 17.0.\n\n### R1. Default Identifiers\n\nThe general Elixir identifier rule is specified as:\n\n    <Identifier> := <Start> <Continue>* <Ending>?\n\nwhere `<Start>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> characters derived from the Unicode General Category of uppercase letters, lowercase letters, titlecase letters, modifier letters, other letters, letter numbers, plus `Other_ID_Start`, minus `Pattern_Syntax` and `Pattern_White_Space` code points\n>\n> In set notation: `[\\p{L}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\nand `<Continue>` uses the same categories as the spec but normalizes them to the NFC form (see R4):\n\n> ID_Start characters, plus characters having the Unicode General Category of nonspacing marks, spacing combining marks, decimal number, connector punctuation, plus `Other_ID_Continue`, minus `Pattern_Syntax` and `Pattern_White_Space` code points.\n>\n> In set notation: `[\\p{ID_Start}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}\\p{Other_ID_Continue}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n`<Ending>` is an addition specific to Elixir that includes only the code points `?` (003F) and `!` (0021).\n\nThe spec also provides a `<Medial>` set, but Elixir does not include any character on this set. Therefore, the identifier rule has been simplified to consider this.\n\nElixir does not allow the use of ZWJ or ZWNJ in identifiers and therefore does not implement R1a. Bidirectional control characters are also not supported. R1b is guaranteed for backwards compatibility purposes.\n\n#### Atoms\n\nUnicode atoms in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Continue>` additionally includes the code point `@` (0040)\n\nNote atoms can also be quoted, which allows any characters, such as `:\"hello elixir\"`. All Elixir operators are also valid atoms, such as `:+`, `:@`, `:|>`, and others. The full description of valid atoms is available in the [\"Atoms\" section in the syntax reference](syntax-reference.md#atoms).\n\n#### Variables, local calls, and remote calls\n\nVariables in Elixir follow the identifier rule above with the following modifications:\n\n  * `<Start>` additionally includes the code point `_` (005F)\n  * `<Start>` additionally excludes Lu (letter uppercase) and Lt (letter titlecase) characters\n\nIn set notation: `[\\u{005F}\\p{Ll}\\p{Lm}\\p{Lo}\\p{Nl}\\p{Other_ID_Start}-\\p{Pattern_Syntax}-\\p{Pattern_White_Space}]`.\n\n#### Aliases\n\nAliases in Elixir only allow ASCII characters, starting in uppercase, and no punctuation characters.\n\n### R3. Pattern_White_Space and Pattern_Syntax Characters\n\nElixir supports only code points `\\t` (0009), `\\n` (000A), `\\r` (000D) and `\\s` (0020) as whitespace and therefore does not follow requirement R3. R3 requires a wider variety of whitespace and syntax characters to be supported.\n\n### R4. Equivalent Normalized Identifiers\n\nIdentifiers in Elixir are case sensitive.\n\nElixir normalizes all atoms and variables to NFC form. Quoted-atoms and strings can, however, be in any form and are not verified by the parser.\n\nIn other words, the atom `:josé` can only be written with the code points `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301`, but Elixir will rewrite it to the former (from Elixir 1.14). On the other hand, `:\"josé\"` may be written as `006A 006F 0073 00E9` or `006A 006F 0073 0065 0301` and its form will be retained, since it is written between quotes.\n\nChoosing requirement R4 automatically excludes requirements R5, R6, and R7.\n\n## Unicode Technical Standard #39\n\nElixir conforms to the clauses outlined in the [Unicode Technical Standard #39](https://unicode.org/reports/tr39/) on Security, version 17.0.\n\n### C1. General Security Profile for Identifiers\n\nElixir will not allow tokenization of identifiers with codepoints in `\\p{Identifier_Status=Restricted}`, except for the outlined 'Additional normalizations' section below.\n\n> An implementation following the General Security Profile does not permit any characters in \\p{Identifier_Status=Restricted}, ...\n\nFor instance, the 'HANGUL FILLER' (`ㅤ`) character, which is often invisible, is an uncommon codepoint and will trigger a warning.\n\n### C2. Confusable detection\n\nElixir will warn of identifiers that look the same, but aren't. Examples: in `а = a = 1`, the two 'a' characters are Cyrillic and Latin, and could be confused for each other; in `力 = カ = 1`, both are Japanese, but different codepoints, in different scripts of that writing system. Confusable identifiers can lead to hard-to-catch bugs (say, due to copy-pasted code) and can be unsafe, so we will warn of identifiers within a single file that could be confused with each other.\n\nWe use the means described in Section 4, 'Confusable Detection', with one noted modification:\n\n> Alternatively, it shall declare that it uses a modification, and provide a precise list of character mappings that are added to or removed from the provided ones.\n\nElixir will not warn about confusability for identifiers made up exclusively of characters in a-z, A-Z, 0-9, and _. This is because ASCII identifiers have existed for so long that the programming community has had their own means of dealing with confusability between identifiers like `l,1` or `O,0` (for instance, fonts designed for programming usually make it easy to differentiate between those characters).\n\n### C3. Mixed Script Detection\n\nElixir will not allow tokenization of mixed-script identifiers unless it is via chunks separated by an underscore, like `http_сервер`. We use the means described in Section 5.1, Mixed-Script Detection, to determine if script mixing is occurring, with the 'Additional Normalizations' documented in.\n\nExamples: Elixir allows an identifiers like `幻한`, even though it includes characters from multiple 'scripts', as Han characters may be mixed with Japanese and Korean, according to the rules from UTS 39 5.1. When mixing Latin and Japanese scripts, underscores are necessary, as in `:T_シャツ` (the Japanese word for 't-shirt' with an additional underscore separating the letter T).\n\nElixir does not allow code like `if аdmin, do: :ok, else: :err`, where the scriptset for the 'a' character is {Cyrillic} but all other characters have scriptsets of {Latin}. The scriptsets fail to resolve and a descriptive error is shown.\n\n### C4, C5 (inapplicable)\n\n'C4 - Restriction Level detection' conformance is not claimed and does not apply to identifiers in code; rather, it applies to classifying the level of safety of a given arbitrary string into one of 5 restriction levels.\n\n'C5 - Mixed number detection' conformance is inapplicable as Elixir does not support Unicode numbers.\n\n### Addition Normalizations\n\nAs of Elixir 1.14, some codepoints in `\\p{Identifier_Status=Restricted}` are *normalized* to other, unrestricted codepoints.\n\nThis is currently only applied to translate MICRO SIGN (`µ`) to Greek lowercase mu (`μ`).\n\nThe normalization avoids confusability and the mixed-script detection is modified to the extent that the normalized codepoint is given the union of scriptsets from both characters.\n\n  * For instance, in the example of MICRO => MU, MICRO was a 'Common'-script character - the same script given to the '_' underscore codepoint - and thus the normalized character's scriptset will be {Greek, Common}. 'Common' intersects with all non-empty scriptsets, and thus the normalized character can be used in tokens written in any script without causing script mixing.\n\n  * The code points normalized in this fashion are those that are in use in the community, and judged not likely to cause issues with unsafe script mixing. For instance, the MICRO or MU codepoint may be used in an atom or variable dealing with microseconds.\n\n<!-- File: .cursorrules (elixir-engineer-guidelines-cursorrules-prompt-file.mdc) (Tokens: ~189 | Category: cursor-rule) -->\n---\ndescription: \"Cursor rules for Elixir development with engineer guidelines.\"\nglobs: **/*\nalwaysApply: false\n---\nAct as an expert senior Elixir engineer.\n\nStack: \nElixir, Phoenix, Docker, PostgreSQL, Tailwind CSS, LeftHook, Sobelow, Credo, Ecto, ExUnit, Plug, Phoenix LiveView, Phoenix LiveDashboard, Gettext, Jason, Swoosh, Finch, DNS Cluster, File System Watcher, Release Please, ExCoveralls\n\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n\nWhere:\n\ntype: One of the following:\n\nscope (optional): A noun describing a section of the codebase (e.g., fluxcd, deployment).\n\ndescription: A brief summary of the change in present tense.\n\nbody (optional): A more detailed explanation of the change.\n\nfooter (optional): One or more footers in the following format:\n</yakaai_skills>"}