Using extensible records in type aliases

I have a project with a lot of very similar but slightly different data types, so I’ve been making a lot of use of extensible records so that, for example, if I have several record types all of which have ids, I can use the same function (with a signature like List {record | id = Id } -> List {record | id = Id }) for all of them for ordering them by id.

Sometimes stuff gets more complicated than that, though, and I’ve recently realized that a lot of the weird errors I’ve struggled with relating to extensible records have been connected to using them in type aliases. I’ve occasionally gotten bewildering errors where I pass something with a type of CoolType that I think is something like { info : Info, otherStuff: OtherStuff } but I get errors that look like:

This value is a:


But `myFunction` needs the 1st argument to be:

    { otherStuff: OtherStuff }

And I find myself thinking, “But CoolType is { info : Info, otherStuff: OtherStuff }, not just { otherStuff: OtherStuff }???”

For example, there’s a type in my code that looks like this:

type alias MoveConfig creation =
    { moving : { creation | info : InfoFields }
    , destination : Position { creation | info : InfoFields }
    , startingList : List { creation | info : InfoFields }

and my instinct in writing it was "this is saying that the creation type should have a field called info with a type of InfoFields. That is, if I then declare a function of type moveItem : MoveConfig MyType -> List MyType, then MyType is required to have an info field of type InfoFields. But with errors like the above, I’m thinking maybe there’s something more subtle going on.

I’m not sure if I’m making this clear, because I don’t understand it well enough myself to narrow it down to a working SSCCE, but hopefully it’s clear enough for any other people who may have seen similar things?

I realized recently that I could solve most of the issues I’ve been having by restricting the use of extensible records to function signatures, and basically never using them in type aliases. So far, this has worked to eliminate the weird type errors I had been seeing.

Two questions:

First, has anyone else seen errors like the above and if so, are you able to explain what’s happening in them?

Second, does a practice of “just never use extensible records in anything other than function signatures” seem reasonable? Does it preclude any important or useful ways of being able to write code in Elm?

1 Like

Definitely reasonable. This advice is commonly given out, and I agree with it.

Leaning too heavily into extensible record types can be an indication that you’re trying to create some faux inheritance system; which definitely not what we want!

1 Like

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