Http.header "" "something" in a List of
headers in elm/http ends up in a runtime exception. I have opened an issue for this.
By the way, while I writing up the issue, I pondered this a little more generally.
Essentially, I wanted to do this:
headers = [ case fooBar of Foo str -> Http.header "foo" str Bar -> Http.header "" "" , ... ]
I.e. Conditionally add/not add a value within a List.
Yes, the runtime exception is avoidable if I rewrite to this:
headers = case fooBar of Foo str -> [ Http.header "foo" str ] Bar -> 
But what if I need to add other elements to the list?
let fooHeaderOrNone = case fooBar of Foo str -> [ Http.header "foo" str ] Bar ->  in [ ... (other headers) ... ] ++ fooHeaderOrNone
Works, but do we add this kind of conditional variables for all non-static parts?
Maybe we should. Since descriptive intermediate variables actually could make a whole part easier to understand.
But it is also very likely that it feels tedious to do so, especially the intent behind those switching is just obvious, and there are only few of them. Also when I am too lazy to think about variable name. Super likely!
(Of course, if there are many switches to toggle, then we should definitely consider breaking it up to descriptive private functions)
As you may noticed, the pattern is very common in
div [ case fooBar of Foo _ -> class "foo" Bar -> class "" , ... ] [ case bazMaybe of Just baz -> bazElement baz Nothing -> text "" , ... ]
Let us call this "
none patterns are very common, common enough for some modules actually provide APIs with exactly that name: notably
Cmd.batch [ staticCmd , case fooBar of Foo foo -> fooCmd foo Bar -> Cmd.none , ... ]
I like them as they are handy for some small, obvious switches inside Lists.
I like them also because they are somewhat format-friendly. Say if we break above code into variables, without using
let fooOrNone = case fooBar of Foo foo -> [ fooCmd foo ] Bar ->  in Cmd.batch ([ staticCmd , ... ] ++ fooOrNone )
Well, it is subjective I admit, but it feels ugly to me, due to introduced parens,
++, and their formatting rules. Of course we can remedy that by introducing an additional variable for static parts:
let staticCmds = [ staticCmd , ... ] fooOrNone = case fooBar of Foo foo -> [ fooCmd foo ] Bar ->  in Cmd.batch (staticCmds ++ fooOrNone)
I am more comfortable with this, but compared to the original style using
Cmd.none within List, it still feels like a roundabout approach. Yes it brings some additional info for readers, but also, visual complexity.
Again, it involves subjective feelings. And if there are more switches in a List, I would happily consider introducing well-structured private functions or
let variables. But if there are only one or two of them,
none pattern could be just enough.
Html.Attributes which do not have
text "" and
class "" (or
style "" "", or even
property "" Json.Encode.null) are widely used for this very purpose. For that, elm-ui even adopted the pattern as
Element.none, which is more sophisticated than just putting
text "", though.
I see questions or discussions about this pattern often, especially around
Html or elm-ui. (e.g. “How can I do the same thing as
Element.none for attributes?”)
And again I found a case where this leads to even runtime exception in the case of current implementation of
So I think it’s worth a consolidated discussion around this.
- Do you like or dislike the pattern, and why?
- When you think you should or should not use this pattern?
- When, or What types of, packages/modules can benefit from this pattern? “Should I consider adding
noneto this package?”
- Is there any possible issues when adopting this pattern?
Personally, I like this pattern for reasons explained above, and hope more packages support
none-equivalent funcitons if they make use of “Listable” types.
elm/http is one of them.
Element.noneAttr in elm-ui would be good to have too. I always introduce it anyway.
Format-friendliness is especially pleasing. When I make views with elm-ui, writing somewhat long attribute lists is quite common, which I hesitate to disrupt with
Appendix: idiom using
Some of you may noticed that it is also possible to mimic
none pattern using
Cmd.batch <| List.filterMap identity <| [ Just staticCmd , case fooBar of Foo foo -> Just (fooCmd foo) Bar -> Nothing , ... ]
I often use this, especially when there are related functions that returns
Maybe a already.