Crowdhailer

Crowdhailer

Creator of Raxx

Is there any semantic meaning to atoms

The short version of this questions is, what is the purpose of atoms?

I know that strings and atoms are represented differently at a low level and that atoms allow quick comparison amongst other benefits. However if all the do is optimize the code then could it be argued that their use is a premature optimization.

There is a cost when translating code that uses atoms to strings and visa versa. The main occasion where this comes up for me is when I have a web form that is decoded with string keys that I want to map to a struct to pass to some domain code.

Ideally I would have the following

sign_up_form = # pull from a request
sign_up = struct(MyApp.SignUp, webform)

However because the sign_up_form has string keys I end up doing something more like

sign_up = %MyApp.SignUp{
  password: sign_up_form["password"]
  username: sign_up_form["username"]
  # etc etc
}

Most Liked

OvermindDL1

OvermindDL1

An atom is basically an integer, nothing more. The runtime has mappings between these integers and a string value, but all comparisons are done on these integer values (literally an integer too if you look at how erlang encodes them at runtime, there is an atom map to do the translations at compile time that things like binary_to_atom look into).

In C parlance it would be like a global:

enum Atoms {
  List,
  All,
  Atoms,
  Here,
}
const char *getStringOfAtom(Atom atom) { ... }

In C++ it would be more accurately a flyweight’d string:

typedef flyweight<std::string> Atom;

Atom someAtom("SomeAtom");

// Use someAtom, compare it, etc..., it is actually a handle into a global atom map,
// which in this case does get 'collected' when all atoms go out of scope because of
// RAII, which BEAM/EVM does not do for efficiency.  But you can get the string back
// from it, compare it fast, whatever...

Although I made a library a while back when C++11 came out that I’ve been using since to give me atom-like things in C++ without any of the runtime or GC or memory costs, except it limits me to a set amount of characters of a maximum length, certainly not as generic as erlang’s atoms, but hey, I can even switch on them (since they are just integers under-the-hood)! The code I have a copy of in my OverECS example project: OverECS/StringAtom.hpp at master · OvermindDL1/OverECS · GitHub

using namespace OverLib::StringAtom;
Atom64 atom{}; // A default-allocated atom is just the empty string ""
atom = "SomeAtom"_atom64; // The "SomeAtom" string as an atom, this happens at compile-time
atom = atomize64("SomeAtom"); // The "SomeAtom" string as an atom, happens at run-time
std::string atomString = deatomize64(atom); // Get the string that the atom represents, this only happens at compile-time
// Yes this works!  And was the original motivating reason too.
switch(atom) {
case "AnAtom"_atom64: blah(); break;
case "SomeAtom"_atom64: blorp(); break;
default: bloop();
}

I used those to great effect in a lot of systems. It is just a simple 5 or 10 char → integer mapping via a mapping table with optional loose(default) or tight encodings, the tight gives you a few extra chars of length in exchange for forcing case-insensitivity. Usually I use flyweight strings for longer ‘interned’ strings that allow for pointer comparisons, which are fast, but when the overhead is too much or I want to store in less space, my atom’s have been awesome. For example I pass around events in some of my projects like this:

void handleEvent(VariantMap event) {
  // This mapping is done at compile-time so it just becomes a quick integer lookup:
  float tick = event["DELTA"_atom64].get<float>(0.0f);
  // This mapping is done at run-time, but still fast:
  float tick = event["DELTA"].get<float>(0.0f);
  // Though for generic things like a DELTA call I actually have a global helper type that does the casting/default/andAllElse:
  float tick = event[DELTA];
}

That is also exposed to LUA and the usage inside a VariantMap makes it very easy to use and make events from inside LUA:

local function handleEvent(event)
  -- Dynamic access, still pretty fast actually
  tick = event["DELTA"]
  -- Using a registered deserialization object, much faster, but does not really matter overall
  tick = event[DELTA]
end

And of course, OCaml has built-in ‘atoms’:

let someAtom = `GlobalAtom

let anotherAtom = `AnotherAtom

Except in OCaml you can also attach additional data to its ‘atom’ (polymorphic variant), basically like a tagged tuple in erlang:

let something = `GlobalAtom 42 

A given atom without data and an atom with data are two different atom types and will not match, say like this:

`Ok (42, "string")
(* Does not match: *)
`Ok 42
(* Does not match: *)
`Ok

Just like:

{:ok, 42, "string"}
# Does not match:
{:ok, 42}
# Does not match:
:ok

Though like in erlang/elixir you can test that it ‘is’ a polymorphic variant, then refine on it if want to get data or not.

So in essence an atom is anything for whatever the context wants it to be.

sasajuric

sasajuric

Author of Elixir In Action

IMO they server as symbolic constants. Something akin to enums from C if you will.

For example, instead of passing around a magical number of 42, we could pass around :meaning_of_life, and convert to integer at the system boundaries, as @michalmuskala explained here just a few minutes ago.

Other examples include tagged tuples (e.g. {:ok, value}, {:error, reason}, reply tuples in behaviours, etc. If atoms didn’t exist, we’d either have to pass magical integers or strings.

Since atoms represent “well known” pieces of information, they are also used in structs or maps as keys representing fields we expect in them.

If you mean the cost of typing, there was some helper library for that (I can’t remember which one though, maybe someone can step in). Otherwise it’s not really hard to write a simple one converter yourself.

Where Next?

Popular in Discussions Top

Donovan
Hello everyone, I’m so glad to have discovered this awesome community. Thanks for creating it! This is my second post, and apologies for...
New
laiboonh
Hi all, I am trying to convince my team to use liveview over the current react. What are some of the points where one should consider us...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
mmport80
I have put far too much effort into Dialyzer over the last year or so - and basically - I doubt it’s worth the effort. It’s not as easy ...
New
lorenzo
Hey everone! I created a prototype for my app using Nodejs for the api. But the framework I chose wasnt great (in general theresnt any g...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
restack_oslo
Hello, Please pardon me for any faux paux. I am 46 and this is my first time on a forum of any kind. I wanted to to get answers from tho...
New
New
axelson
Decided against including more info in the title, but the gist is that Plataformatec sponsored projects will continue with the assets bei...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31013 112
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement