# Understanding extensible records

**URL:** <https://discourse.elm-lang.org/t/understanding-extensible-records/4709>\
**Category:** Learn\
**Created:** [November 21, 2019, 10:35am UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709 "2019-11-21T10:35:58Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![GabeAtWork](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gabeatwork/32/2940_2.png) [@GabeAtWork](https://discourse.elm-lang.org/u/GabeAtWork)\
**Post date:** [November 21, 2019, 10:35am UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/1 "2019-11-21T10:35:58Z")

</div>

Hi there!

I’m trying to understand how to use extensible records to do what I want. Here’s a quick example of the situation I’m in:

```auto
module Foo exposing (..)

type alias Foo =
    { name : String
    }

type alias Selectable a =
    { a
        | isSelected : Bool
    }

isSelectableSelected : Selectable a -> Bool
isSelectableSelected selectable =
    selectable.isSelected

getFooName : Foo -> String
getFooName foo =
    foo.name

makeSelectableFoo : Selectable Foo
makeSelectableFoo =
    { name = "Bar"
    , isSelected = True
    }

getMyFooName =
    let
        selectableFoo =
            makeSelectableFoo
    in
    getFooName selectableFoo

```

This does not compile, with the following error:

```auto
-- TYPE MISMATCH --------------------------------------------------- src/Foo.elm

The 1st argument to `getFooName` is not what I expect:

37| getFooName selectableFoo
                   ^^^^^^^^^^^^^
This `selectableFoo` value is a:

    Selectable Foo

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

    { name : String }

Hint: Seems like a record field typo. Maybe isSelected should be name?

Hint: Can more type annotations be added? Type annotations always help me give
more specific messages, and I think they could help a lot in this case!

```

I’m trying to find a way to write `getFooName` in a way that allows me to use it with whichever extended type I choose (`Selectable` for instance). As far as this function is concerned, anything with `name` property should work out, because all it cares about is whether the argument has the structure of a `Foo` (which only has a name).

I understand I could make it work with making a `Fooable` type alias and having a bogus “base type”:

```auto
module Foo exposing (..)

type alias Bar =
    {}

type alias Fooable a =
    { a
        | name : String
    }

-- ....

getFooName : Fooable a -> String
getFooName foo =
    foo.name

makeSelectableFoo : Selectable (Fooable Bar)
makeSelectableFoo =
    { name = "Bar"
    , isSelected = True
    }

getMyFooName =
    let
        selectableFoo =
            makeSelectableFoo
    in
    getFooName selectableFoo

```

This gives me the behaviour I want, but I’ve had to create a bogus empty record type and “Fooable” doesn’t make as much sense as Foo.

How is this type of problem typically solved?

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [November 21, 2019, 10:43am UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/2 "2019-11-21T10:43:38Z")

</div>

You don’t really need to define types, you could write `getFooName` as:

```elm
getFooName : { r | name : String } -> String
getFooName foo =
    foo.name

```

and it would work with any record with a `name : String` field.

But actually there is already a syntax for such functions in the language itself, check in `elm repl`:

```auto
> .name
<function> : { b | name : a } -> a

```

So `.name` is exactly that, and uses extensible records. You can use `foo.name` or `.name foo`.

```auto
> .name { name = "foo" }
"foo" : String

> { name = "foo" }.name
"foo" : String
```

---

<div class="post-metadata">

**Author:** ![GabeAtWork](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gabeatwork/32/2940_2.png) [@GabeAtWork](https://discourse.elm-lang.org/u/GabeAtWork)\
**Post date:** [November 21, 2019, 11:07am UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/3 "2019-11-21T11:07:04Z")

</div>

Thank you for your reply! I hadn’t thought about defining `getFooName`'s argument as an extensible record itself. I’ll keep that in mind!

For my real use case however, the burden I was trying to avoid was redefining `Foo`'s fields elsewhere - I should have been clearer about that in my original post.

In a situation where `Foo` has 10 fields, all of which are used in this hypothetical `getFooName`, say I’m writing 5 functions like `getFooName`, repeating these 10 fields definition 5 times. Now if I change or add a field to `Foo`, I have to make 5 changes. (While not as extreme, my real-world use case defines 3 fields, but is used in 9 places, some of which use it as `Selectable`, some of it not.)

On the other hand, in the example, if I added or changed a field in `Selectable`, there’s only 1 place I’d need to change a definition, since `isSelectableSelected` (and every other function I could have written that used `Selectable`) doesn’t redeclare those fields. I am trying to find a way to get the same level of practicality for a base type alias as with an extended record.

It doesn’t seem feasible this way, but I must admit I’m curious as to why the compiler doesn’t permit the passing of a “bigger record” to a function as long as it defines the required fields.

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [November 21, 2019, 11:13am UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/4 "2019-11-21T11:13:50Z")

</div>

I’m not sure to understand, but I could have written:

```elm
getFooName : Fooable a -> String
getFooName foo =
    foo.name

```

It would have been the same, without repeating the fields.

You can also make a `type alias Foo = Fooable {}`, and then use `Foo`, and all your hypothetical functions could use a `Fooable a` without repeating the fields:

```auto
module Foo exposing (..)

type alias Fooable a =
    { a
        | name : String
        , age : Int
    }

type alias Foo =
    Fooable {}

type alias Selectable a =
    { a
        | isSelected : Bool
    }

isSelectableSelected : Selectable a -> Bool
isSelectableSelected selectable =
    selectable.isSelected

getFooName : Fooable a -> String
getFooName foo =
    foo.name ++ String.fromInt foo.age

makeSelectableFoo : Selectable Foo
makeSelectableFoo =
    { name = "Bar"
    , age = 42
    , isSelected = True
    }

getMyFooName =
    getFooName makeSelectableFoo

```

in `elm repl`:

```auto
> import Foo
> Foo.getMyFooName
"Bar42" : String

```

Note: again, in this meaningless example, `isSelectableSelected = .isSelected`. It could use more fields though in a real use-case.

That said, extensible records have their use, but rarely as a data modeling one. So beware, you may reach some dead-ends trying to do this. They are mostly useful for narrowing functions arguments ([https://medium.com/@ckoster22/advanced-types-in-elm-extensible-records-67e9d804030d](https://medium.com/@ckoster22/advanced-types-in-elm-extensible-records-67e9d804030d)).

---

<div class="post-metadata">

**Author:** ![GabeAtWork](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gabeatwork/32/2940_2.png) [@GabeAtWork](https://discourse.elm-lang.org/u/GabeAtWork)\
**Post date:** [November 21, 2019, 12:14pm UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/5 "2019-11-21T12:14:24Z")

</div>

That is pretty nice and works well to avoid redefining the fields, thank you! The only downside that remains is the relation between `Foo` and `Fooable`. It won’t necessarily be intuitive for a newcomer to understand the difference between the two.

I suppose extensible records are not really made for this use case. For now on my real-life project, I’ve kept a record with `isSelected` defined in, without extensible records, as it’s much simpler. Only downside is, I have to sometimes provide bogus `isSelected` data just so I can pass it to some functions.

I’ll keep on coding and I might find a better way to solve the underlying problem 👷‍♂️

---

<div class="post-metadata">

**Author:** ![dmy](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dmy/32/702_2.png) [@dmy](https://discourse.elm-lang.org/u/dmy)\
**Post date:** [November 21, 2019, 12:18pm UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/6 "2019-11-21T12:18:44Z")

</div>

Yeah, Elm works usually better with flat models (without nested extensible records or nested fields).

Bogus data should be avoided. A simple way would be to use a `Maybe Bool` for the model selection status and for `isSelected`. It might be preferable though to use a custom type like:

```auto
type Selection
    = Unselectable
    | Unselected
    | Selected

```

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [December 1, 2019, 12:18pm UTC](https://discourse.elm-lang.org/t/understanding-extensible-records/4709/7 "2019-12-01T12:18:50Z")

</div>

Closed on December 1, 2019, 12:18pm UTC

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