https://github.com/sabiwara/cmp
Semantic comparison and sorting for Elixir
https://github.com/sabiwara/cmp
comparison elixir-lang sorting
Last synced: 6 months ago
JSON representation
Semantic comparison and sorting for Elixir
- Host: GitHub
- URL: https://github.com/sabiwara/cmp
- Owner: sabiwara
- License: mit
- Created: 2023-03-04T06:19:39.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-05-25T03:51:39.000Z (over 1 year ago)
- Last Synced: 2024-10-07T13:07:58.578Z (about 1 year ago)
- Topics: comparison, elixir-lang, sorting
- Language: Elixir
- Homepage:
- Size: 35.2 KB
- Stars: 25
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Cmp
[](https://hex.pm/packages/cmp)
[](https://hexdocs.pm/cmp/)
[](https://github.com/sabiwara/cmp/actions?query=workflow%3ACI)Semantic comparison and sorting for Elixir.
## Why `Cmp`?
The built-in comparison operators as well as functions like `Enum.sort/2` or
`Enum.max/1` are based on Erlang's term ordering and suffer two issues, which
require attention and might lead to unexpected behaviors or bugs:### 1. Structural comparisons
Built-ins use
[structural comparison over semantic comparison](https://hexdocs.pm/elixir/Kernel.html#module-structural-comparison):```elixir
iex> ~D[2020-03-02] > ~D[2019-06-06]
falseiex> Enum.sort([~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]])
[~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]]
```Semantic comparison is available but not straightforward:
```elixir
iex> Date.compare(~D[2019-01-01], ~D[2020-03-02])
:ltiex> Enum.sort([~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]], Date)
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
````Cmp` does the right thing out of the box:
```elixir
iex> Cmp.gt?(~D[2020-03-02], ~D[2019-06-06])
trueiex> Cmp.sort([~D[2019-01-01], ~D[2020-03-02], ~D[2019-06-06]])
[~D[2019-01-01], ~D[2019-06-06], ~D[2020-03-02]]
```### 2. Weakly typed
Built-in comparators accept any set of operands:
```elixir
iex> 2 < "1"
trueiex> 0 < true
trueiex> false < nil
true
````Cmp` will only compare compatible elements or raise a `Cmp.TypeError`:
```elixir
iex> Cmp.lte?(1, 1.0)
trueiex> Cmp.lte?(2, "1")
** (Cmp.TypeError) Failed to compare incompatible types - left: 2, right: "1"
```## Installation
`Cmp` can be installed by adding `cmp` to your list of dependencies in
`mix.exs`:```elixir
def deps do
[
{:cmp, "~> 0.1.3"}
]
end
```The documentation can be found at
[https://hexdocs.pm/cmp](https://hexdocs.pm/cmp).## Design goals
- Fast and well-optimized - the overhead should be quite small over built-in
equivalents. See the `benchmarks/` folder for more details.
- No need to require macros, plain functions
- Easily extensible through the `Cmp.Comparable` protocol
- Robust and well-tested (both unit and property-based)Supporting comparisons between non-homogeneous types such as mixed `Decimal` and
built-in numbers for instance is a non-goal. This limitation is a necessary
trade-off in order to ensure the points above. Use the `Decimal` library
directly if you need this.## Copyright and License
Cmp is licensed under the [MIT License](LICENSE.md).