4 ms·
I'm not missing it, I just don't like it. It makes the language difficult to understand when any given time you run into an atom, maybe it's being used like a
by aetherson 10y ago
I'm not missing it, I just don't like it. It makes the language difficult to understand when any given time you run into an atom, maybe it's being used like a ruby symbol (such as the way the initial :ok gets used in the examples I pasted), but maybe it's being used as a module.
My problems with __MODULE__ are, first, it's just super clumsy to have heavily used language constructs with lots of underscores around them, and I don't really understand why anyone ties themselves to that particular semantic. I hate it in Python, too. Almost any other way of distinguishing it from other language elements would be less jarring to read.
But second, %__MODULE__{ buffer | size: buffer.size + 1, queue: :queue.push(buffer.queue, whatever) } does some kind of magic that I'd have to look up the details of, but basically copies buffer but overrides some of its elements, right? That's why you don't have to set max_size explicitly? It's a hack that lets you have actually immutable objects but deal with a logically mutable buffer. It's a weird combination of verbose (to copy buffer, I have to write %__MODULE{ buffer, where in another language it might be like buffer.copy()), and compact to the point of overly dense information (I'm putting a lot of expressions on one line), and it's implicit, too -- what parts of buffer are being copied over unchanged? Sorry, better go and look somewhere else. I think this is legitimately hard to get right -- the immutability constraint means that a lot of the standard idioms of programming are a poor fit -- but ultimately this is Elixir's job.
- sasa555 10y agoThe atom always means the same thing - a symbolic (named) constant. The dot operator can be used on an atom type to invoke a function from the corresponding module. A capital Foo.Bar is called an alias in Elixir, and it's the same as an atom :"Elixir.Foo.Bar". The usage of __MODULE__ is optional. You can also write %Buffer.Ets{...} if you prefer. There's no hidden magic with %__MODULE__{buffer | ...}. It's an "update" syntax which allows you to take an existing "struct" (essentially a bunch of well-known named fields), and create a transformed version of it with some fields changed. The code %__MODULE__{buffer | size: buffer.size + 1} is therefore the same as %Buffer.Ets{buffer | size: buffer.size + 1}, and it evaluates to a transformed buffer with the size field set to the size of the original buffer incremented by 1. The original buffer is left intact (since you can't do in-place data mutation in Elixir). However, the transformed version is not a full deep copy of the original. It's going to share as much data as possible with the original version. Hope that helps :-)
- ericmj 10y agoThere seems to be confusion here about the language semantics. There is no mutability in the expressions you have shown. buffer.copy() would not make sense since the language is immutable, why would you want an explicit copy mechanism when every update is essentially being performed on a copy.