#Help Understanding Generic Custom Types

1 messages · Page 1 of 1 (latest)

dreamy gorge
#

Hi. I'm working my way around Lustre (and gosh is it awesome!). I'm new to Gleam (and statically typed languages in general - though I've several years of Elixir/BEAM) and I'm struggling to understand the following return signature....

fn view(model: Model) -> Element(Msg) {
let count = int.to_string(model.count)

html.div([], [
html.button([event.on_click(UserClickedIncrement)], [html.text("+")]),
html.p([], [html.text(count)]),
html.button([event.on_click(UserClickedDecrement)], [html.text("-")]),
])

I know MSG is one of my message types e.g. UserClickedIncrement but I can't tie Element(Msg) to what I believe is a chunk of HTML. I'm obviously missing something.

Could someone help explain this or point me to somewhere on the Web that might explain it.

Many thanks

paper lotus
#

My understanding is that the elements need to know what kind of msg they send and receive in events. In this case, the event.on_click function accepts a callback that returns a Msg.

https://hexdocs.pm/lustre/lustre/event.html#on_click shows that on_click accepts a generic msg type. on_click returns an Attribute(msg) which has the same generic type. (pay attention to capitalization here; the lowercase msg is a generic type that could be replaced with anything, and is unrelated to the specific uppercase Msg you have defined.

When you are using it with a UserClickedIncrement (I assume this is a constructor of one variant in the Msg type), that gets specialized so that on_click in this case has to be a function that accepts a Msg and returns an Attribute(Msg). That Attribute(Msg) is accumulated into part of an Element. Since Element has to hold Attribute, it also needs the generic Msg type.

supple burrow
#

could you post more relevant code, such as your Msg type?

dreamy gorge
#

@supple burrow sure can. The Msg type is....

#

type Msg {
UserClickedIncrement
UserClickedDecrement
}

#

It is taken straight from the Lustre docs.

supple burrow
#

ah

#

is your break in understanding why you don't go from Element(Msg) to HTML directly?

#

I'm not sure I fully understand the question

dreamy gorge
#

@supple burrow - it is more what does Msg have to do with anything.

#

If I have an even simpler view

#

fn view(_model: Model) -> Element(Msg) {
html.div([], [html.text("Hello")])

}

supple burrow
#

Right, ok

dreamy gorge
#

then this also returns a Element(Msg) but where does Msg come from?

ocean bridge
#

In that case, you would probably return Element(a), indicating that this HTML is generic and is not tied to any specific message type

supple burrow
#

yeah Element needs to be generic over Msg since you can only add event handles such as on_click that in turn use that message

winter dawn
#

Elements can dispatch messages

ocean bridge
#

But in your original message, you are using your Msg type in the on_click events. That Msg type is indicates what type of messages the elements can dispatch

winter dawn
#

And the type of the message is parameterised

#

If you passed some other value that wasn’t a Msg into the on_click function you’d have a different message type

supple burrow
#

Yeah it's so that the lustre rendering loop is always consistent over Msg

winter dawn
#

If you got rid of the on_click entirely it would be generic again with no specific message type

supple burrow
#

Hope we're not confusing you haha @dreamy gorge

dreamy gorge
#

So Msg is there because you "might" pass a message (as in the on_click) - why doesn't Gleam complain when I don't pass a message as in the second simpler example?

#

@supple burrow - not at all - super helpful - really want to understand how this is all put together.

supple burrow
dreamy gorge
#

Thanks all - I think the fog is clearing a little - I'm going to see if I can pull together a toy example to help me really understand this 🙂

supple burrow
#

yeah, just let us know if you need help!

lost surge
#

Not all variants (constructors) of a generic type reference the type parameter. Here's a simpler example that is also fine:

fn wibble() -> option.Option(a) {
  option.None
}

fn wobble() -> option.Option(Int) {
  wibble()
}
ocean bridge
dreamy gorge
#

Thanks @lost surge and @ocean bridge - I think I'm starting to get it.