# Type mismatch when calling passed auxilliary func, not when hardcoding the reference to it

**URL:** <https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624>\
**Category:** Learn\
**Created:** [February 1, 2024, 11:51am UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624 "2024-02-01T11:51:05Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![masa331](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/masa331/32/5130_2.png) [@masa331](https://discourse.elm-lang.org/u/masa331)\
**Post date:** [February 1, 2024, 11:51am UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/1 "2024-02-01T11:51:05Z")

</div>

Hi everybody,

i’m in the middle of rewriting something into Elm and i run into a weird thing where i get a Type mismatch when calling a function passed as an argument but not if i hardcode the reference(sorry for wrong term maybe) to the same function in the caller instead.

Following code is very simplified to reproduce the problem:

```auto
type Model
  = Counter1 Counter1Data
  | Counter2 Counter2Data

type alias Counter1Data =
  { count : Int
  , foo : String
  }

type alias Counter2Data =
  { count : Int
  , bar : String
  }

```

So my model is a tagged union where both Counter1 and Counter2 have similar but not the same data.

Now i have a view and two ancilliary functions which look like that:

```auto
model = Counter1 { count = 0, foo = "" }

view : Model -> Html Msg
view model =
  let
    updated = updateCounter model
  in
    case updated of
      Counter1 data -> Html.text (String.fromInt data.count)
      Counter2 data -> Html.text (String.fromInt data.count)

updateCounter model =
  case model of
    Counter1 data ->
      Counter1 (increment data)

    Counter2 data ->
      Counter2 (increment data)

increment : { a | count : Int } -> { a | count : Int }
increment a =
  { a | count = a.count + 1 }

```

So these two ancialliary functions just increment my model and like that it compiles fine and shows the incremented counter on the screen properly.

But when i change the code so that the increment function is not hardcoded in updateCounter but is instead passed to it it crashes with Type Mismatch error:

```auto
updateCounter updateFunc model =
  case model of
    Counter1 data ->
      Counter1 (updateFunc data)

    Counter2 data ->
      Counter2 (updateFunc data)

increment : { a | count : Int } -> { a | count : Int }
increment a =
  { a | count = a.count + 1 }

view : Model -> Html Msg
view model =
  let
    updated = updateCounter increment model
  in
    case updated of
      Counter1 data -> Html.text (String.fromInt data.count)
      Counter2 data -> Html.text (String.fromInt data.count)

```

And also ti crashes the same way when i’m trying to pass the increment function as lambda:

```auto
updateCounter updateFunc model =
  case model of
    Counter1 data ->
      Counter1 (updateFunc data)

    Counter2 data ->
      Counter2 (updateFunc data)

view : Model -> Html Msg
view model =
  let
    increment a =
      { a | count = a.count + 1 }
    updated = updateCounter increment model
  in
    case updated of
      Counter1 data -> Html.text (String.fromInt data.count)
      Counter2 data -> Html.text (String.fromInt data.count)

```

Also in Ellie here: [https://ellie-app.com/qbPNjPpz7FSa1](https://ellie-app.com/qbPNjPpz7FSa1)  
Second case(crashing): [https://ellie-app.com/qbQq7kdCH5ra1](https://ellie-app.com/qbQq7kdCH5ra1)

What am i missing here? Why does it work in the first example but not in the second and third?

Thank you!

---

<div class="post-metadata">

**Author:** ![masa331](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/masa331/32/5130_2.png) [@masa331](https://discourse.elm-lang.org/u/masa331)\
**Post date:** [February 1, 2024, 11:52am UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/2 "2024-02-01T11:52:07Z")

</div>

Also third Ellie with the third case(also crashing): [https://ellie-app.com/qbQqkmCRKJda1](https://ellie-app.com/qbQqkmCRKJda1)

I couldn’t include more than 2 links in my first post…

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [February 1, 2024, 12:30pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/3 "2024-02-01T12:30:49Z")

</div>

The first thing I’m noticing when looking at your code, is that you don’t annotate your `updateCounter` function. Let’s do that first!

```elm
updateCounter : ({ a | count : Int } -> { a | count : Int }) -> Model -> Model
updateCounter updateFunc model =
  case model of
    Counter1 data ->
      Counter1 (updateFunc data)

    Counter2 data ->
      Counter2 (updateFunc data)

```

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [February 1, 2024, 12:31pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/4 "2024-02-01T12:31:42Z")

</div>

## How annotations work

The use of type definitions like `a` might seem flexible at first, but it’s easy to get mistakes. Let’s look at your `increment` code first:

```elm
increment : { a | count : Int } -> { a | count : Int }
increment a =
  { a | count = a.count + 1 }

```

This code says, _“hey! You can use me on any object `a` as long as it has a `count` field! Doesn’t matter what!”_ and the compiler will take that into account. So if it sees your first implementation:

_IMPLEMENTATION 1 THAT SUCCEEDS_

```elm
updateCounter : Model -> Model
updateCounter model =
  case model of
    Counter1 data ->
      Counter1 (increment data)

    Counter2 data ->
      Counter2 (increment data)

```

The compiler looks at the two lines and thinks _“oh right, I can fit `Counter1Data` in `{ a | count : Int }`, so that works. Also, I can fit `Counter2Data` in `{ a | count : Int }`, so that works.”_ That’s why the compiler succeeds.

## Where it goes wrong

Let’s look at the 2nd Ellie example - the one that goes wrong. When you annotate the function, the compiler throws a different error.

_IMPLEMENTATION 2 THAT FAILS_

```elm
updateCounter : ({ a | count : Int } -> { a | count : Int }) -> Model -> Model
updateCounter updateFunc model =
  case model of
    Counter1 data ->
      Counter1 (updateFunc data)

    Counter2 data ->
      Counter2 (updateFunc data)

```

The compiler says _“hey, that’s a `Counter1Data`, not a `{ a | count : Int }`! That’s not the same!”_ Which is very confusing because it seems to contradict what we see in your first example. **But it’s not the same thing!**

You need to keep in mind that the compiler takes the definition of `{ a | count : Int }` **very** seriously in both functions. In example 1, you may not use any other fields like `foo` or `bar`; only `count` can be used. In the second example, you may also not assume that `{ a | count : Int }` has any other fields like `foo` and `bar`; hence you may not use `updateFunc` on a `Counter1Data` or a `Counter2Data`. _(In your example, it ONLY refuses `Counter2Data` because the lack of annotation makes it assume that `updateFunc` is a `Counter1Data -> Counter1Data` type.)_

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [February 1, 2024, 12:43pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/5 "2024-02-01T12:43:19Z")

</div>

## An obvious example

For obvious reasons, we want `updateCounter` to fail if you pass the following function as its `updateFunc` argument, even though it’s perfectly legal according to the type annotation:

```elm
wrongUpdateFunc : Counter1Data -> Counter1Data
wrongUpdateFunc data =
    { count = data.count + 1, bar = "bar" }

```

This would obviously fail horribly! And since the compiler has to accept that `updateCounter` CAN take a function like this as its argument, you can’t just use it on a `Counter1Data` or `Counter2Data` type at the same time.

---

<div class="post-metadata">

**Author:** ![masa331](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/masa331/32/5130_2.png) [@masa331](https://discourse.elm-lang.org/u/masa331)\
**Post date:** [February 1, 2024, 2:49pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/6 "2024-02-01T14:49:52Z")

</div>

Hi Bram, thank you very much for your replies. I updated the annotations and the error changed a bit but it still doesn’t make any sense to me.

> The compiler says _“hey, that’s a `Counter1Data`, not a `{ a | count : Int }`! That’s not the same!”_ Which is very confusing because it seems to contradict what we see in your first example. **But it’s not the same thing!**

How come it’s not the same? I mean i get that they are not the same but `Counter1Data` is a record with two fields - `count` and `foo`. And `{ a | count : Int }` is a record which has at least a field `count` of type `Int` right? Then `Counter1Data` matches with `{ a | count : Int }` because it has that field.

> You need to keep in mind that the compiler takes the definition of `{ a | count : Int }` **very** seriously in both functions. In example 1, you may not use any other fields like `foo` or `bar`; only `count` can be used.

I don’t get the point here. The `increment` function isn’t using anything else than `count` field and compiler can see that and i would expect that is the reason why it’s allright with it in the first working example. Because it knows from the definitions that both `Counter1Data` and `Counter2Data` have the field. Btw i would expect(and it would make sense) if the compiler complaints when the function tries to manipulate fields which are not present in both types. But that is not the case, so it’s ok.

> In the second example, you may also not assume that `{ a | count : Int }` has any other fields like `foo` and `bar`; hence you may not use `updateFunc` on a `Counter1Data` or a `Counter2Data`.

This is confusing for me. In the second example the compiler can also see the definition of `increment` function(in fact it’s the same function) so it must know there is no code trying to manipulate fields which are not there. It only manipulates fields which are present in both `Counter1Data` and `Counter2Data` so what is the difference?

> **An obvious example** …

Yes, here it makes sense to me that the compiler would complain because i’m trying manipulate fields which are not present in all the types it works with.

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [February 1, 2024, 3:14pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/7 "2024-02-01T15:14:15Z")

</div>

> [@masa331](#):
>
> How come it’s not the same? I mean i get that they are not the same but `Counter1Data` is a record with two fields - `count` and `foo`. And `{ a | count : Int }` is a record which has at least a field `count` of type `Int` right? Then `Counter1Data` matches with `{ a | count : Int }` because it has that field.

The compiler interprets `{ a | count : Int }` as “whoever uses this function, can insert **ANY** record as long as it has a `count` field of type `Int`.”

So `updateCounter : ({ a | count : Int } -> { a | count : Int }) -> Model -> Model` means "whoever uses this function, can insert **ANY** function with **ANY** record as input and output as long as it has `count` field of type `Int`. Which is not the case for you: you mean to say “whoever uses this function, must insert a function that supports **ALL** records that have a `count` field of type `Int`.”

And that’s where the compiler complains (in a un-Elm-like unclear manner). Conceptually, you are saying that you want `updateCounter` to work even if I, as an ignorant programmer, insert my function `wrongUpdateFunc` into `updateCounter`.

---

<div class="post-metadata">

**Author:** ![Bram](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bram/32/4862_2.png) [@Bram](https://discourse.elm-lang.org/u/Bram)\
**Post date:** [February 1, 2024, 3:19pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/8 "2024-02-01T15:19:47Z")

</div>

> [@masa331](#):
>
> This is confusing for me. In the second example the compiler can also see the definition of `increment` function(in fact it’s the same function) so it must know there is no code trying to manipulate fields which are not there. It only manipulates fields which are present in both `Counter1Data` and `Counter2Data` so what is the difference?

So when you say `updateFunc` is of type `{ a | count : Int } -> { a | count : Int }`, and you use it on `Counter1Data`, the compiler says “a is not Counter1Data”.

It’s basically saying _“how do you know that `updateFunc` is compatible? What if it isn’t? You don’t know if `a` is `Counter1Data` or that the function is able to deal with it!”_

---

<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:** [February 11, 2024, 3:20pm UTC](https://discourse.elm-lang.org/t/type-mismatch-when-calling-passed-auxilliary-func-not-when-hardcoding-the-reference-to-it/9624/9 "2024-02-11T15:20:12Z")

</div>

Closed on February 11, 2024, 3:20pm UTC

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