Dealing with state duplication within the model (The Elm Architecture)

277 views
Skip to first unread message

Werner de Groot

unread,
Apr 8, 2016, 6:30:22 AM4/8/16
to Elm Discuss
Hi guys,

I have a problem with dealing with a piece of state duplication, in which I want to keep both in sync.

I have a

    type alias Employee = { firstName: String, lastName: String, salary: Double }


    type
alias Company = { name: String, employees: List Employee }


which I use in one part of the application. In another (a view in which a user can add new employees to the company or change salaries) I have

    type alias EditableEmployee = { firstName: String, lastName: String, salary: Double, warningsAndErrors: List String, isInEditMode: Boolean }


(an EditableEmployee has some extra pieces of information that are relevant to editing a list of employees).

Let's say my model is like this:

    type Model = Model Company (List EditableEmployee)

As you can see, a lot of state is duplicated. Now, if I add an employee (or change the salary of one) through a EditableEmployee, how can I best update the Employees in the Company? What are ways to normalize the model without suffering a big performance penalty?


Max Goldstein

unread,
Apr 8, 2016, 8:18:32 AM4/8/16
to Elm Discuss
Try giving each employee a unique ID. Keep an incrementing int in your model if you have to.

When you edit an employee, the ID goes with it. Dict.update (for ID keys) will nicely let you "upsert" to either the old employee or create a new one.

I wouldn't worry too much about duplicated state since until the employee edit is saved you need the old version. That said if Editable Employee could have an Employee record as a subfield that might allow you to change them more easily.

Werner de Groot

unread,
Apr 8, 2016, 9:42:36 AM4/8/16
to Elm Discuss
Thanks for the response!

I'm afraid I explained my problem badly. Or oversimplified it.

Let's try to add some additional context:

The problem is that, in my actual problem, the Employees are located rather deep in the model, and might even be duplicated multiple times (suppose, for instance, Company also has a Dict (Month, Year) Employee for the employee of the month). I'm struggling with ways to notify all Employee-instances that something might have changed. It is difficult to know, at the root Model, how to find all Employee-instances (and would give the root Model too much knowledge of its children anyway).

In Object Oriented Programming (stateful programming) I would probably use events. The above problem reduces to letting every Employee-instance subscribe to some EmployeesChangedEvent once and they would always be notified automatically. This is not so easy in Elm where we need a whole new version of the Model, not just a new version of an Employee.

Maybe I should make a special Action for these kinds of events (EmployeeAddedAction, EmployeeChangedAction) and another event handler-function for every model that reacts to these Actions? 

A further problem is that there are many values which have a "true" representation and an "editable" representation, like Employee. Consequently, there are a lot of additional Actions that need a seperate event handler. This solution obviously doesn't scale well.

I feel like I'm trying to do something very un-Elm-like, struggling with this problem. I'm hoping that there is an obvious approach to these sorts of problems that I'm missing (or that I'm doing something odd with my Model)

Op vrijdag 8 april 2016 14:18:32 UTC+2 schreef Max Goldstein:

Max Goldstein

unread,
Apr 8, 2016, 9:51:01 AM4/8/16
to Elm Discuss
Well, instead of all of those copies of employees, could you store the ID instead, and then look up the employee in a dictionary? This gives you a single point of truth, but you have to handle a Maybe Employee from the lookup.

Werner de Groot

unread,
Apr 8, 2016, 9:55:12 AM4/8/16
to elm-d...@googlegroups.com
Doesn't that mean that you have to pass a Dict with Employee-instances (and many more Dict-instances like it) to every part of the view that, at some point, needs it to send an action or render something related to an Employee?

2016-04-08 15:51 GMT+02:00 Max Goldstein <maxgol...@gmail.com>:
Well, instead of all of those copies of employees, could you store the ID instead, and then look up the employee in a dictionary? This gives you a single point of truth, but you have to handle a Maybe Employee from the lookup.

--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/DPuz9Ky6EDs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

John Orford

unread,
Apr 8, 2016, 10:11:56 AM4/8/16
to elm-d...@googlegroups.com
How about storing all your employees at the top level. Then have have action 'interupts' relating to lower lever components at that top level to manipulate employees.

That's what came up with at least. Not fully satisfied, still thinking about improvements


You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Werner de Groot

unread,
Apr 8, 2016, 10:14:05 AM4/8/16
to elm-d...@googlegroups.com
Glad to see I'm not the only one struggling with these kinds of questions.

Could you explain a little bit more about your solution? What do you mean with "interupts"?

John Orford

unread,
Apr 8, 2016, 10:43:28 AM4/8/16
to elm-d...@googlegroups.com

See the analysis action here, it also refers to an analysisform component lower down

https://github.com/mmport80/Lazy-PCA/blob/master/web/elm/Router.elm

David Legard

unread,
Apr 8, 2016, 8:23:43 PM4/8/16
to Elm Discuss
The problem is that, in my actual problem, the Employees are located rather deep in the model, and might even be duplicated multiple times (suppose, for instance, Company also has a Dict (Month, Year) Employee for the employee of the month).

 To solve that, you could move ownership of the "Employee of the Month award" to the Employee type

That is, in your record type for Employee, you would add

type alias Employee =
{ name :string
 
,age : integer
..
awards
: List Award
.. }

and

type alias Award = {description : string, month : int, year : int}

Then, it's simple to pluck the right Employee out for any given month or year.

One of the biggest challenges for me when starting to work with Elm/Haskell/F# was trying to "think functionally", where there's no mutability and no global scope. Once you get that, data structures fall into place and the code goes with it.

The second issue, of altering a value deep in a record stack, like:

Company -> Employee -> Salary is a major topic of discussion. We'd like to write:

myCo.myEmp.salary <- 25


but we can't.

Elm has some work going on in this area

hossameldeenfci

unread,
Apr 8, 2016, 8:51:28 PM4/8/16
to Elm Discuss
Solutions to Horizontal scaling might give ideas.
Reply all
Reply to author
Forward
0 new messages