arashm

arashm

I read the “Programming Elixir” book, here is quote from the book:

At some point, the old object-orientation neurons still active in the nether regions of your brain might burst into life and you might think, “Hey, this is a bit like a class definition.” And you’d be right. You can write something akin to object-oriented code using structs (or maps) and modules.
This is a bad idea. Not because objects are intrinsically bad, but because you’ll be mixing paradigms and diluting the benefits a functional approach gives you.

Having this in the back of my mind, today I’m making a simple app which relies on data comes from a JSON API. The data structure is deeply nested and the API on different end-points uses different keys for same objects (imagine in one it returns name in another it returns title). So I thought I’d convert those JSON data to different structs and define a to_normalized_struct function in those to convert them to a struct that provides a same interface to be used through out the app.

But then… I thought maybe I’m coding OO here and may face wrath of functional programming gods later. So when is right to use structs? How would you implement the code for above problem?

Showing Posts 1 to 7

bbense

bbense

My 2 cents. The way out of the OO trap is to think data and transformations.

I can’t answer your specific question w/o knowing the larger context, it might make sense to simply create a transform function for each JSON type to a standardized data form. Or it might make sense
to avoid the central form and just make transforms that extract the data you need.

The way to answer that question is to think about any transforms you need for the resulting data. What data structure makes the most “sense” in your problem? Rather than modeling “things”[1], start thinking about transforms and the inputs and outputs they need.

The Struct construct handy in that it provides both an easy to read access syntax and it constrains your transforms to a specific set of keys in a Map. However, the problem with Struct is the dual of it strengths, you lose the ability to dynamically change the structure of the data as the problem evolves. Struct requires that you “model” the problem in advance. This is not a terrible thing; in fact the strong type people would claim this is a very good thing. It does take away some of the flexibility and power of a dynamic language.

So as a practical guide, I’d suggest that if you are either constantly adding fields to your Struct or creating many slightly different, but almost the same structs, then you probably don’t understand the problem well enough yet to use a struct. The other thing to be aware of is that Struct only constrains the keys, not the values. If you find yourself putting wildly different values under the same struct key, then you’re probably in the weeds.

[1]- Experience suggests this is also the source of most problems with OO design as well.

AstonJ

AstonJ

I am just going through the Elixir and Phoenix Bootcamp course and in my notes I have written:

Structs

Just like Maps but with 2 advantages:

  • Can be assigned default values
  • Additional compile-time checking of properties

If we know the properties we are going to be working with we will use a Struct instead of a Map.

peerreynders

peerreynders

elixir-lang: Structs

Structs are extensions built on top of maps that provide compile-time checks and default values.

Maps aren’t necessarily less OO than Structs - it’s all about how you use them.

OO on the other hand will often manage and encapsulate “state” within object instances - so if most of your “transformations” look like they are simply advancing the state of a thing that is represented by a single key-value collection then there may be cause for concern because the ultimate judgement is context sensitive. For example it is accepted practice that a single key-value collection can represent the state of an Elixir process.

I think sloppy terminology isn’t helping in this case. While it’s called “JavaScript Object Notation” JSON doesn’t contain objects in the OO sense because an OO object collocates data and the functions that operate on it - JSON isn’t allowed to contain any functions - so you are left with pure data. Also does “name” and “title” actually return data that is identical or do they merely return data that has the same shape - i.e. given that “name” and “title” fulfill a similar role do they simply use the same data type?

arashm

arashm OP

It returns identical data. Imagine an API endpoint for searching products, and one for getting info about an specific product. The former returns an array of products and latter returns one product. One of them has name attribute and the other title but with same value and purpose.

bbense

bbense

That’s a valid point, the way that I tend to divy it up is to think of the flows within the application. Each flow or path through the application will likely require it’s own unique data structure; if you’ve got one GIANT map that is passed through multiple flows, then that’s probably a warning flag in the opposite direction. You can write the GOD object in any language (i.e. fortran common )

peerreynders

peerreynders

[quote=“arashm, post:5, topic:2396”]
One of them has name attribute and the other title but with same value and purpose.[/quote]

:rolling_eyes:
I would lean towards parsing the data in both cases into a generic Map and then generating the normalized structure from the data in the Map. I’d basically end up with 3 modules, one for the normalized struct, one for the product collection conversion and one for the single product conversion - possibly a fourth for commonalities between the last two - depends on how (in)consistent they are.

Though not necessary, I would typically expect more than one data structure/shape per flow. As the data moves through the transformation pipeline the shape tends to pick up derived/looked up details that drive towards the desired end result.

slashdotdash

slashdotdash

A useful comparison of structs and maps is made in When to Use Structs, String-keyed Maps, and Atom-keyed Maps.

It lists six rules governing the best practice usage of these data structures.

  1. Always Use String-Keyed Maps for External Data.
  2. Convert External Data to Structs ASAP.
  3. Use Structs in All Other Code.
  4. Use Structs for Output Data.
  5. Avoid Using Atom-keyed Maps That Aren’t Structs.
  6. Use Keyword Lists Only for Function Arguments
— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews