# `Feel.Analysis.Identity`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/analysis/identity.ex#L1)

A value compared with itself (D-170): `x = x` is `true` and `x != x` is `false`, for every value of FEEL, `null` included.

`Feel.Runtime.Compare.equal/2` has no shortcut for two values that are the same one: it walks lists and contexts
element by element. A value that is built from itself (`{a0: [1, 2], a1: [a0, a0], …, a22: [a21, a21]}`) is 23
cells in the VM and 2^22 numbers when it is walked, so `a22 = a22` was ten seconds of one step, that no limit saw. An
operand that is read twice is the same value both times, so the answer is known without reading it. The order of
`<`, `<=`, `>` and `>=` is not an identity (`null < null` is `null`, and `true <= true` is `null`), so it is not the constant:
`ordering/4` has the type that the same read gives for the kinds that have an order (D-170).

Two operands are the same read when they are the same node, but for its `meta`:

  * a constant that is the same term, or a name of the bindings (`{:var, _, name}`) with the same name;
  * a `:local` of the same name and the same depth (`meta.id`, D-193), which is the binding of one construct;
  * a selection by the same name (`p.a`, not `p.(a)`) from the same read;
  * a list of the same length of the same reads, if the run can make it (`max_list_length`);
  * a context literal with the same keys in the same order, of the same reads, that is not an error (D-58).

A call is never one, whatever it is called with: it is counted by `max_calls` and by the diagnostics, and `now()`
and `uuid()` give another value the second time. Nor is anything that binds a name inside the operand (an iterator, a
function), a filter, an `item`, a `partial`, a descendant, or an operation: when in doubt, the comparison is made.

And only for values of FEEL. A name of type `Any` can be bound to a term that is not one (a float, an atom, a decimal
that is a NaN: `Feel.Runtime.Kind.of/1` is `:unknown` for it, and `x = x` is `null` with a type mismatch), and the soundness
sweeps run the analysis on such values (`scripts/sweep/dispatch.exs`). So the type of the operand has to say that every value
of it is a value of FEEL: no `Any`, no `:foreign`, and no name of a model type in it, at any depth. A type that is too large to
look through (a tower of contexts) is not looked through, and the comparison is made. A list and a context, open or closed, are
values of FEEL whatever their elements and entries are: `Compare.equal/2` answers `true` for a list or a context that is the same
term before it looks at an element or an entry (D-168), so a `p` that is a declared context and has an entry of any kind, and an
`xs` of `list<Any>` that holds a float, are equal to themselves (D-170). A range is walked, and its ends are looked at.

What the comparison tells depends on whether the reads can report:

  * **silent**: constants, locals, the lists and the contexts of them, and a selection from a silent read whose type
    has no `null` in it (a selection reports an error only where it gives `null`). The two reads settle nothing
    and report nothing, so the comparison is the constant (`{:const, _, true}`).
  * **reads**: a name of the bindings, which reports a name that is not bound (D-37) at each of the two reads, and
    what is built on it. The type of the comparison is `true` and the node stays, so that the run reports what it
    did (D-45, D-53).

What it does not see: two operands that are alike but are not the same read (`a22 = b22` for two towers built apart,
`xs[1] = xs[1]`), and the same value that comes from two calls. They are compared by the run.

    iex> {:ok, ast} = Feel.parse("{a: [1, 2], b: [a, a], r: b = b}")
    iex> {:ok, %{ir: {:context, _, entries}}} = Feel.Analysis.Analyzer.analyze(ast, [])
    iex> {"r", {:const, %{type: type}, value}} = List.last(entries)
    iex> {type, value}
    {[{:boolean, true}], true}

# `reads`

```elixir
@type reads() :: :constant | :silent | :reads
```

What the reads of two operands that are the same can report. `:constant` is for two constants only.

# `comparison`

```elixir
@spec comparison(atom(), Feel.IR.t(), Feel.IR.t(), Feel.Limits.t()) ::
  {:silent | :reads, boolean()} | :none
```

What `left <operator> right` is when the two operands are the same read: whether the reads can report, and the value of
the comparison. `:none` when they are not, or the operator is not `=` or `!=`.

    iex> local = fn -> {:local, %{span: {0, 1}, type: [:number], id: 1}, "a"} end
    iex> Feel.Analysis.Identity.comparison(:eq, local.(), local.(), Feel.Limits.default())
    {:silent, true}
    iex> var = fn -> {:var, %{span: {0, 1}, type: [:number]}, "x"} end
    iex> Feel.Analysis.Identity.comparison(:neq, var.(), var.(), Feel.Limits.default())
    {:reads, false}
    iex> Feel.Analysis.Identity.comparison(:lte, var.(), var.(), Feel.Limits.default())
    :none

# `ordering`

```elixir
@spec ordering(atom(), Feel.IR.t(), Feel.IR.t(), Feel.Limits.t()) ::
  {:ok, Feel.Type.Union.t()} | :none
```

The type of `left <operator> right` for `<`, `<=`, `>` and `>=` when the two operands are the same read of a value of a kind
that has an order (D-170): `false` for `<` and `>`, and `true` for `<=` and `>=`, and `null` where the value is, since an
ordering with a `null` is `null`. It is not an identity as `=` is, because of that `null`, and so the node stays and the run
makes it. `:none` when the operands are not the same read, or the type has a kind without an order, which
is a mismatch (a boolean, a list, a context, a range, a function), or one that is not known (`Any`).

The two reads have to have one type, as they have in one place.

    iex> var = fn type -> {:var, %{span: {0, 1}, type: type}, "x"} end
    iex> Feel.Analysis.Identity.ordering(:lt, var.([:number, :null]), var.([:number, :null]), Feel.Limits.default())
    {:ok, [{:boolean, false}, :null]}
    iex> Feel.Analysis.Identity.ordering(:gte, var.([:date]), var.([:date]), Feel.Limits.default())
    {:ok, [{:boolean, true}]}
    iex> Feel.Analysis.Identity.ordering(:lte, var.([:boolean]), var.([:boolean]), Feel.Limits.default())
    :none
    iex> Feel.Analysis.Identity.ordering(:lt, var.([:any]), var.([:any]), Feel.Limits.default())
    :none

# `same_value?`

```elixir
@spec same_value?(Feel.IR.t(), Feel.IR.t(), Feel.Limits.t()) :: boolean()
```

Whether two operands are one read of a name, or of a member of one (`p.age`), so that they are the same value (D-170): the
operands of `x - x`, which is `0` for every `x`, and not the difference of two numbers of the type of `x`. The same
reads as `comparison/4` takes, but for the ones that are made of other things than names: a constant, a list and a
context are not here, since arithmetic on them is folded or a mismatch, and a list is dear to look through.

    iex> var = fn name -> {:var, %{span: {0, 1}, type: [:number]}, name} end
    iex> Feel.Analysis.Identity.same_value?(var.("x"), var.("x"), Feel.Limits.default())
    true
    iex> Feel.Analysis.Identity.same_value?(var.("x"), var.("y"), Feel.Limits.default())
    false
    iex> path = fn name -> {:path, %{span: {0, 1}, type: [:number]}, var.("p"), name} end
    iex> Feel.Analysis.Identity.same_value?(path.("age"), path.("age"), Feel.Limits.default())
    true

---

*Consult [api-reference.md](api-reference.md) for complete listing*
