Hi everyone. I’m a (very) new elixir programmer but I’m really enjoying it so far. I have a question on idiomatic Elixir. If this isn’t the right place to post this question, sorry in advance!
I’m cutting my teeth with a basic “Store” application (think grocery store). It has an inventory of items, and clients can connect to the store and buy them, adding them to their inventories. Super simple.
I’m struggling with how best to represent “Currency” or “Value”. Items in the store have value, and clients have money to buy those items. I want to use gold, silver and copper coins. In an OOP language I would make them objects and maybe subclass coin. In OCaml/Haskell I would probably use a variant type:
type coin = Gold of int | Silver of int | Copper of int
My current thinking is to make a “Value” module with a struct representing the total value, and functions to manipulate it. Then each item in the store has a Map with its info, including a Value field, and each Client has an Inventory with an associated Value representing their total money.
What @Nobbz said, if you wanted the OCaml form in Elixir you’d make them as:
{:Gold, value}
{:Silver, value}
{:Copper, value}
Although I’d bet you would actually prefer the record form that you did in Elixir so you can mix them together. Although optimally you would reduce it down to a single integral value so you could take mixtures of the gold/silver/copper rather than only specific amounts.
I’m not sure if using a single integral value is sufficient.
Lets consider a situation where one has 100 cents. Even though the value is equivalent to a dollar, the person working at wallmarts might deny to accept them.
So in fact, I think the struct were the most appropriate thing to use.
Depends on your definition of OOP but in my eyes, it isn’t – OOP would be if you have an object plus methods encapsulated, while in FP languages you have a module that works with any instance of the structure (which is incidentally defined in the same module; that link isn’t a given, it’s just a convenient default which FP programmers use all the time) and the module’s state itself isn’t affected in any way.
Only thing I’d change is to make as detailed typespecs as possible – dialyzer isn’t perfect but it can help you catch a class of logical problems early.
Thanks – perhaps my OCaml example wasn’t the best. Or maybe I’m just missing sum types
I hadn’t thought of a tagged tuple. In the example you give, it seems like Value is the name of a module, but not a struct of that module. So – I’d use the name of a module as the tag for my tuple? Is this a normal pattern in elixir?
The example with {:Gold, value} etc doesn’t specify a set of possible variants. So it’s possible a {:Platinum, value} might be passed to a function expecting only :Gold, :Silver, :Copper. Would the idea be that those functions pattern match on the three possibilities to “enforce” the “type” of the coin?
For a single integral value, would it make sense to use rem/2 and div/2 to pull it apart? So copper is rem(value, 1000), silver is rem(div(value,1000),1000) and gold is value/1000000? (Assuming 1000 copper to a silver), and then I just pass around an integer?
The idiom (since the erlang days) is to use an atom that uniquely identifies the record. In most cases the atom is the modulename that implements most functions around the “datatype”.
For modules that implement many of those, often a suffix is used.
Precisely. Elixir is not strongly typed so you enforce constrains by matching and guards at runtime instead.
That’s what I’d for a simple little game coinage system, although I personally like nice round numbers like 1024 or 8192 or so (base 10 is so weird to do math in to me, I grew up with powers of 2… though personally I think base 6 is awesome but nothing uses it). ^.^;