If you want a string literal, then just write a string literal. They and atoms, are both immutable and unassignable. Atoms are bound to get abused, simply to avoid writing quotes around string literals.
If atoms are enum members, then when one is created, firstly some implicit Enum class in that scope needs to be instantiated behind the scenes, for the new atom to be a member of. Then secondly when another atom is defined, the scope’s implicit enum class must be mutated to add the new member (currently Enums’re immutable as one would expect).
I can see atoms help you reason about Elixir code. But we can already reason about Python code by examining the namespace. Normally (without globals or locals hacking) new names are only introduced by the assignment statement (=) or the import statement. Atom syntax would be an extra thing to remember, that doesn’t add much and breaks a fundamental useful rule of thumb.
Elixir uses Enum to mean something far more like a Python Iterable. But in Python “enum” means “one of a finite number of possibilities”. Where as atoms could be any valid Python name, and are only defining one possibility.
A huge benefit of Atoms and Python enum members, comes from using them in conjunction with type hints. The best practise for Enum function args, would be to still define the ‘class’, and then use that as a type annotation.
Does Elixir have an identity (e.g. is) operator? The behaviour of is with enum members in Python has been carefully implemented. It’s easy enough to adjust __eq__ to ensure that as in Elixir :red == 'red', but I think the best thing to do would be to have :red is not 'red'. Otherwise then presumably I could call any string method on it, e.g. :red.upper() etc. If red: is 'red' then red: behaves differently to a Python enum member.
Anyway, I may not like the colon syntax currently, and I see problems in breaking immutability, and in using it both as sugar for an enum member, and having it to be a string literal. But I still like the general idea.
I’d just prefer a const key word. const red = "red" is self explanatory, and more in line with “explicit is better than implicit” than :red