With this utility, you can replace hex colors such as
#606060 with
#000000 (black) using the sidebar at the left. It uses global search/replace within the file. There is no undo functionality, so simply reload your file to start over. A preview appears below.
Open an html file or load the example to begin.
- or -
Preview
Readme
TypeCheck
A small Elixir utility to identify the type of a given value.
“Your idea is a good one! … There is no built-in or standard module
in Elixir that directly provides this functionality.
The implementation fills this niche by providing a straightforward
way to identify the type of a value in a human-readable form (as an
atom), which can be particularly useful for debugging or logging
purposes.
TypeCheck module serves a unique purpose that isn’t directly covered
by Elixir’s standard library or built-in functions, making it a valuable
addition, especially for specific use cases or educational
purposes.”
Reasoning
This project provides a simple function to determine the type of a
value in Elixir. It’s particularly useful for scenarios where
understanding the specific type of a value is necessary, such as in
dynamic data handling or debugging.
Using TypeCheck.check streamlines code by replacing
verbose case statements and multiple is_* type
checks with a single, clear line of code. This not only enhances
readability but also reduces redundancy.
Limitations
The TypeCheck.check function may return nil
for certain Elixir types or constructs that don’t fit into standard
types, like certain process-related constructs, externally defined
types, or special constructs in Elixir internals. The function does not
return :number as Elixir distinguishes between
:integer and :float, and all numbers will fall
into one of these categories.
Usage
value =:example_atomtype =TypeCheck.check(value)IO.inspect(type)# Outputs: :atom
More complex usage
Without TypeCheck, handling different types might
involve verbose and repetitive case statements with
multiple is_* type checks:
# without TypeCheckdef handle_value(value)docase value do v when is_integer(v)->"Received an integer: #{Integer.to_string(v)}" v when is_float(v)->"Received a float: #{Float.to_string(v)}" v when is_atom(v)->"Received an atom: #{Atom.to_string(v)}" v when is_binary(v)->"Received a string: #{v}" _ ->"Received an unrecognized type"endend# Example callshandle_value(100)# "Received an integer: 100"handle_value(3.14)# "Received a float: 3.14"handle_value(:hello)# "Received an atom: hello"handle_value("world")# "Received a string: world"Despite abbreviating value as v (a common convention), the above remains redundant and difficult to read.WithTypeCheck, this can be streamlined significantly:# with TypeCheckdef handle_value(value)docaseTypeCheck.check(value)do:integer->"Received an integer: #{Integer.to_string(value)}":float->"Received a float: #{Float.to_string(value)}":atom->"Received an atom: #{Atom.to_string(value)}":binary->"Received a string: #{value}" _ ->"Received an unrecognized type"endendEliminating the print statements the difference between#without TypeCheckdef handle_value(value)docase value do v when is_integer(v)->Integer.to_string(v) v when is_float(v)->Float.to_string(v) v when is_atom(v)->Atom.to_string(v) v when is_binary(v)-> v _ ->nilendend# with TypeCheckdef handle_value(value)docaseTypeCheck.check(value)do:integer->Integer.to_string(value):float->Float.to_string(value):atom->Atom.to_string(value):binary-> value _ ->nilendendThis is more ergonomic, resulting in a reduction of 13% of the code (15 characters).## Compatibility guaranteesAll currently supported types will continue to return their current value.In the future, specialized types that currently return nil could instead return a new atom, however existing atoms will not be removed.## Future Compatibility GuaranteesCommitment to reliability and stability is paramount for \`TypeCheck\`.The following guarantees are provided to ensure future compatibility:-**ConsistentSupportforCurrentTypes**: All types currently identifiable by \`TypeCheck\` will continue to be supported in future versions.This means any type that \`TypeCheck\` can presently identify will remain identifiable in all future releases.-**ExtensibilityforNewTypes**: Recognizing the dynamic nature of Elixirand potential future developments, \`TypeCheck\` may be updated to include new Elixir types, particularly those currently returning \`nil\`.Any such updates will aim for backward compatibility.-**NoRemoval of Types**: There will be no removal of existing type checks in future versions.This ensures that existing code relying on \`TypeCheck\` will continue to function correctly with new versions of the module.This approach is aimed at providing a dependable and forward-compatible tool that aligns with the growth of the Elixir ecosystem, while maintaining stability for existing projects.## HistoryDecember2023Initial proof of concept was made via the simplified function:defmoduleTypeCheckdodef check(value)do type_checks =[{&is_integer/1, :integer},{&is_float/1, :float},{&is_atom/1, :atom},{&is_tuple/1, :tuple},{&is_list/1, :list},{&is_map/1, :map},{&is_binary/1, :binary},{&is_function/1, :function},{&is_pid/1, :pid},{&is_reference/1, :reference}]Enum.reduce(type_checks, nil, fn{func, type_atom}, acc ->if func.(value), do: type_atom, else: accend)endendHowever, the list of checks provided by Kernel is incomplete for example it does not include Regex, there is no is_regex() check.The list is available here:https://hexdocs.pm/elixir/1.15.7/Kernel.htmlI made a study of how inspect works, the file is located here:https://github.com/elixir-lang/elixir/blob/main/lib/elixir/lib/inspect.ex and saw that it uses a protocol with different implementations for different types so I decided to do the same thing, even though this meant switching my implementation.I retained the previous version for cross-validation purposes, since two alternative implementations are more likely to be valid and this way my tests could also catch any errors in implementation of any of the kernel functions, should such errors be introduced.## InstallationIf[available inHex](https://hex.pm/docs/publish), the package can be installedby adding \`type_check\` to your list of dependencies in \`mix.exs\`:\`\`\`elixirdef deps do[{:type_check, "~> 0.1.0"}]end