Why not components?

731 views
Skip to first unread message

Wouter In t Velt

unread,
Dec 4, 2016, 6:50:06 AM12/4/16
to Elm Discuss
Hi All,
To explore and explain (in a beginner-friendly way) why making stateful reusable components in Elm is not always a good idea,

I have made a demo + write-up in 2 articles over on Medium.

Here are the links to the drafts:

Any feedback would be welcome!

Rex van der Spuy

unread,
Dec 4, 2016, 9:02:02 AM12/4/16
to Elm Discuss
Thanks so much for writing that up!
This is exactly the point in my Elm learning that I'm struggling with at the moment, so this extremely helpful.
In the past I've always made my "components" as self-contained M/U/V modules - that was great because I could re-use them in other projects just by dropping the .elm module file into my new project folder and it would just work.
So if I needed a button, I'd just drop my button from Project A into Project B, and voila!
I had been building my own little library of these components.
And, I *love* the fact that sub-modules have exactly the same M/U/V structure as the parents modules in a kind of fractal nested way - that makes my code really easy for me to understand.
But, I always found updating submodules and bubbling up their effects a bit of a chore, so I'm looking forward to exploring the (seemingly?) simpler world of pure components.

But.. I'm still a bit confused! :)
I found both Evan's sortable table example and your (excellent!) dropdown menu just a few levels too advanced for my poor beginner's brain to fully grok.

I have a request!
Could anyone point me to a blindingly, brain-dead-simple example of this system in action?
For example, what would a simple, stand-alone, reusable, "pure" button component look like that just triggers a message update in the parent module when clicked?

Wouter In t Velt

unread,
Dec 4, 2016, 9:28:22 AM12/4/16
to Elm Discuss
Op zondag 4 december 2016 15:02:02 UTC+1 schreef Rex van der Spuy:
I found both Evan's sortable table example and your (excellent!) dropdown menu just a few levels too advanced for my poor beginner's brain to fully grok.

Glad you liked it! Were there any particular sections in the article that you found too advanced?
I'd be happy to make them more clear.
 
For example, what would a simple, stand-alone, reusable, "pure" button component look like that just triggers a message update in the parent module when clicked?

A pure reusable button could look like this:
-- the pure button component
type
alias Config msg =
 
{ clickMsg : msg
 
, buttonText : String
 
}

myButton
: Config msg  -> Html msg
myButton config buttonText
=
  button
[ onClick config.clickMsg ] [ text config.ButtonText ]


-- usage in your main module
type
Msg =
 
...
 
| HandleButtonClick

buttonConfig
: Button.Config Msg
buttonConfig
=
 
{ clickMsg = HandleButtonClick
 
, buttonText = "click me!"
 
}

view
: model -> Html Msg
view model
=
  div
[]
   
[ p [] [ text "this is an example" ]
   
, Button.myButton buttonConfig
   
]

I'd put the message and the text both in a config, because I suspect these would be quite static, meaning the values would not change while running you app.

Peter Damoc

unread,
Dec 4, 2016, 9:43:40 AM12/4/16
to Elm Discuss
On Sun, Dec 4, 2016 at 1:50 PM, Wouter In t Velt <wouter....@gmail.com> wrote:
Any feedback would be welcome!

You're trading one set of boilerplate for another. 
Both your versions are almost as bad as you are forcing internal details of the functioning of the dropdown onto the user of the dropdown. 
The pure version is indeed more aligned with the current recommendations but it is almost as bad from a library user point of view. 
In the 5 months since this pattern emerged I have not seen an explosion of "not-a-component" libraries that follow it. 

In order to have a full treatment of the issue, implement a webcomponents/polymer version of the same functionality and then argue that the "pure" version is better. 





--
There is NO FATE, we are the creators.
blog: http://damoc.ro/

Wouter In t Velt

unread,
Dec 4, 2016, 10:51:58 AM12/4/16
to Elm Discuss
Op zondag 4 december 2016 15:43:40 UTC+1 schreef Peter Damoc:

You're trading one set of boilerplate for another. 

Fair enough. I could have pointed that out in the conclusions.

Both your versions are almost as bad as you are forcing internal details of the functioning of the dropdown onto the user of the dropdown. 

Could you explain this? I am not sure I follow what you are saying here. Wouldn't we always enforce some kind of API from the dropdown on the user?
Or what would need to be different in both versions to not "force internals .. onto the user" ?

The pure version is indeed more aligned with the current recommendations but it is almost as bad from a library user point of view. 

Taking the pattern and consequences from a dropdown to a library is something that I did not consider. Maybe I should have.
 
In order to have a full treatment of the issue, implement a webcomponents/polymer version of the same functionality and then argue that the "pure" version is better.

By no means did I intend to make a full treatment of the issue, or claim that pure is always better than stateful.
Admittedly, the wording of the last paragraphs was too strong, so I changed that.

I follow the uptake of integrating web components/ polymer with much interest. 
The argument in the article was made specifically where the dev is building everything in elm, and wants to structure his/her code when the app grows.
The implementation of a Polymer version is a different scenario IMHO. 
But thank you for the challenge, I'll look into it ;)

 

David Andrews

unread,
Dec 5, 2016, 7:29:48 AM12/5/16
to elm-d...@googlegroups.com
A tiny note: To avoid the confusing inclusion of `Position` in `Blur`, you can remove the `Position` and pass `always Blur` to `Mouse.clicks`.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Peter Damoc

unread,
Dec 5, 2016, 8:05:32 AM12/5/16
to Elm Discuss
Wouter, 

After I found out about elm-polymer library, I tried to reimplement your example but, I've run into issues. 

This is as far as I got
https://github.com/pdamoc/polymer-exploration

The problems are due to the way children are handled.  
I tried a fix that I remembered from a previous exploration (lazyRegister) but, the rendering is still bad. 

This is yet another reason I think that Polymer might not be the best way forward. 
A native Elm solution to Web Components might produce better results both in therms of developer UX and in terms of final deliverables. 


--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rupert Smith

unread,
Dec 5, 2016, 9:20:13 AM12/5/16
to Elm Discuss
On Monday, December 5, 2016 at 1:05:32 PM UTC, Peter Damoc wrote:
After I found out about elm-polymer library, I tried to reimplement your example but, I've run into issues. 

This is as far as I got
https://github.com/pdamoc/polymer-exploration

The problems are due to the way children are handled.  
I tried a fix that I remembered from a previous exploration (lazyRegister) but, the rendering is still bad. 
 
Not sure what the problem is, perhaps just styling? I have defeintely been able to get paper-listbox and paper-item working. See:


Relevant source files:


Peter Damoc

unread,
Dec 5, 2016, 9:36:21 AM12/5/16
to Elm Discuss
On Mon, Dec 5, 2016 at 4:20 PM, 'Rupert Smith' via Elm Discuss <elm-d...@googlegroups.com> wrote:
Not sure what the problem is, perhaps just styling? I have defeintely been able to get paper-listbox and paper-item working. See:



Well... duh... I forgot to import them. I'll try to finish the implementation and get back.  

Wouter In t Velt

unread,
Dec 5, 2016, 9:54:54 AM12/5/16
to Elm Discuss
Wow you guys are fast!
Hopefully I can dive into it tonight (@work right now).

I think it would be really interesting to see a webcomponents version of the same example and compare it with the other two versions.

In the meantime, do let me know if there's anything I could improve about my other implementation of the 2 versions.
You are no doubt way more seasoned in Elm than I am, so I am sure my code can be improved.

Peter Damoc

unread,
Dec 5, 2016, 10:58:34 AM12/5/16
to Elm Discuss
I just pushed the latest changes and the functionality should be equivalent. 
https://github.com/pdamoc/polymer-exploration

I have paid very little thought to the Dropdown's API and so it's bad but... it get's the job done. 
Also, I was getting some weird JSON errors when I tried to use official `onIronSelect` and so I just hacked everything to use the onClick. 
These hacks are less important right now as this is the job of the library developer. 

From a library user point of view however, I think that the web-components version is remarkably better.  
With a battery of great looking and easy to combine components like these, one could quickly implement great looking layouts AND, more importantly, quickly alter them without having to change code in multiple places. 



--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rex van der Spuy

unread,
Dec 5, 2016, 12:18:27 PM12/5/16
to Elm Discuss
Thanks so much, your simple button example is extremely helpful!!


Wouter In t Velt

unread,
Dec 5, 2016, 12:25:08 PM12/5/16
to Elm Discuss
This looks very promising!
I really like the fact that the web components solution takes care of the blur stuff, so it makes model cleaner and we can do away with the subscription.

I have to do some more digging, but I like the fact that there's a ton of event handlers, that you can simply include in your elm view render.

Wouter In t Velt

unread,
Dec 5, 2016, 1:38:10 PM12/5/16
to Elm Discuss
Op maandag 5 december 2016 16:58:34 UTC+1 schreef Peter Damoc:
I just pushed the latest changes and the functionality should be equivalent. 
https://github.com/pdamoc/polymer-exploration

Looks great! I would suggest a small change in the country update: to only reset the city selector if the country selected is different from the previous selection.

        CountryPicked country ->
            { model 
            | country = Just country
            , city = 
                if model.country /= Nothing && model.country /= Just country then
                    Nothing
                else
                    model.city
            }


Would have liked to get some sort of onSelectedChanged event working, but even though the event is in the elm-polymer library, I had no luck getting it to work.
Also, would have loved to make a pull request for you repository on github, but I worry that my pull request would include the gazillion bower and npm installs as well.
Sorry, I'm a noob at github too.

Wouter In t Velt

unread,
Dec 5, 2016, 1:40:06 PM12/5/16
to Elm Discuss
Peter, did you deliberately choose to put everything (including items) in a single config record?
Just curious.

Peter Damoc

unread,
Dec 5, 2016, 4:16:43 PM12/5/16
to elm-d...@googlegroups.com
I started out with a bunch of parameters but if I have more than 3 parameters in a function I tend to move towards using a record. As I already pointed out, the API smells. :-)

On Mon, 5 Dec 2016 at 20:40, Wouter In t Velt <wouter....@gmail.com> wrote:
Peter, did you deliberately choose to put everything (including items) in a single config record?
Just curious.

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Peter Damoc

unread,
Dec 5, 2016, 4:51:02 PM12/5/16
to Elm Discuss
On Mon, Dec 5, 2016 at 8:38 PM, Wouter In t Velt <wouter....@gmail.com> wrote:
Looks great! I would suggest a small change in the country update: to only reset the city selector if the country selected is different from the previous selection.

        CountryPicked country ->
            { model 
            | country = Just country
            , city = 
                if model.country /= Nothing && model.country /= Just country then
                    Nothing
                else
                    model.city
            }


You cannot use comparison on tags. But I have updated the code to reflect the requested functionality. It looks like: 


        CountryPicked country ->
            { model
                | country = Just country
                , city =
                    model.country
                        |> Maybe.andThen
                            (\currentCountry ->
                                if currentCountry == country then
                                    model.city
                                else
                                    Nothing
                            )
            }


Wouter In t Velt

unread,
Dec 5, 2016, 4:59:13 PM12/5/16
to Elm Discuss
Op maandag 5 december 2016 22:51:02 UTC+1 schreef Peter Damoc:
You cannot use comparison on tags.

I can see your version is cleaner.
Do you mean a comparison with a maybe is not allowed? Like this?
-- is this not allowed?
if someMaybe == Just 42 then
 
...

The original change I made did seem to work at my end, and the compiler didn't complain..
Or is it convention rather than rule?

Peter Damoc

unread,
Dec 5, 2016, 5:39:13 PM12/5/16
to Elm Discuss
This is weird. 
For some reason I got it into my head that tags are not comparable.
Now I can't remember when or why. 

The code seams to work on my end too and for my sanity I checked it on 0.17 and 0.16 and it works in those versions too. 
weird. 




--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

David Andrews

unread,
Dec 6, 2016, 2:54:17 PM12/6/16
to elm-d...@googlegroups.com
They have equality but not comparison.  They can't be used as a Dict key, for instance.

Wouter In t Velt

unread,
Dec 6, 2016, 3:15:26 PM12/6/16
to Elm Discuss
Thanks for solving this mystery for us David.
It probably is sensible to avoid anyway:

if someMaybe == ... then

And use

case someMaybe of

(Or .map)
instead. Gives us more protection from the compiler to get all branches covered...

Reply all
Reply to author
Forward
0 new messages