Reference items from a list

I’m developing a website that should list dance events. The backend will return something like:

{
    "locations": [
        {
            "id": 1,
            "name": "Chico Mendès",
            "address": "Pontstraße 74-76, 52062 Aachen"
        },
        {
            "id": 2,
            "name": "Sencillito",
            "address": "Alexander Strasse 109, 52066 Aachen"
        }
    ],
    "events": [
        {
            "id": 1,
            "name": "Anfängerkurs",
            "teaser": "Für diejenigen, die Lindy Hop ausprobieren möchten.",
            "description": "Unter Anleitung werden dir die Grundschritte des Lindy Hops beigebracht.",
            "occurrences": [
                {
                    "id": 1,
                    "start": 1554140700,
                    "duration": 45,
                    "location": 1
                },
                {
                    "id": 2,
                    "start": 1554748200,
                    "duration": 90,
                    "location": 2
                }
            ]
        },
        {
            "id": 2,
            "name": "Social Dance",
            "teaser": "Einfach Lindy Hop tanzen.",
            "description": "Hier triffst du viele andere Menschen, die ebenfalls Lust haben, Lindy Hop zu tanzen.",
            "occurrences": [
                {
                    "id": 3,
                    "start": 1554143400,
                    "duration": 90,
                    "location": 1
                },
                {
                    "id": 4,
                    "start": 1554748200,
                    "duration": 90,
                    "location": 2
                }
            ]
        }
    ]
}

The troublesome part is that each occurrence’s location is referenced by id. The only choices I see is to inline the location into each occurrence, or look up a occurrence’s location by id each time I need it. Inlining causes redundancy and prevents me from changing a location in a central place. Keeping the ids means, that I always need to deal with the possibility that the id is invalid.

This is a case, where a reference would be nice, but as can be seen in Rust, doing this safely requires a lot of additional concepts like lifetimes. I could hack around the issue, by keeping the ids and using a Dict Id Location that upon each lookup I chain into a Maybe.withDefault someGarbageLocation. But this is a hack, and I was wondering whether there was a more elegant approach to this issue?

You will eventually have to deal with the fact that the look-up can fail. The backend can send you garbage accidentally and you need to take this into account.

The two options that you have identified come each with its own set of advantages and disadvantages and you need to weight them carefully in order to select the best approach.

For example, the redundancy introduced can be a big waste of memory but if the structures are small enough that will not matter as much. As for “prevents me from changing a location in a central place”, you can have all this data in a session/context/taco record and a single place of update that would take care of refreshing the stale inlined copies automatically.

Ideally I would check the backend’s data once upon reception. Then I know whether it is valid or not. I don’t want to keep checking ids every time I look something up.

I think I will go with the Dict hack for now. I can encapsulate that in a module, as you suggested, such that I can switch to a better implementation, when I find one.

But I would be interested in other ideas for how to deal with this.

You could use the Dict approach without chaining it with a dummy default and handle the Maybe in the consumer.

so, you could have


viewLocation : Id -> Dict Id Location -> Html Msg
viewLocation id locations = 
    case Dict.get id locations of 
        Nothing -> 
            text "error retrieving location" -- or just text "" 
        Just location -> 
            div [][ p [] [ text location.name], p [] [text location.address] ]

or, you could use Maybe.map and chain with a Maybe.withDefault (text "")

viewLocation :  Location -> Html Msg
viewLocation location = 
     div [][ p [] [ text location.name], p [] [text location.address] ]

viewOccurrence occurrence locations = 
    div [] 
        [ Dict.get occurrence.location locations 
            |> Maybe.map viewLocation 
            |> Maybe.withDefault (text "")
        ]

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.