Platform’s batch function has the following type signature:
batch : List (Cmd msg) -> Cmd msg
But what does it return? From the type signature it can only possibly do one of the following:
return a none value of type Cmd msg (e.g. Platform.none)
return one of the provided Cmd msg values, if the List was not empty
The empty list case rules out the second approach but even if it didn’t that would raise the questions about which of the provided values to use.
So it must return a none value? If that’s the case since none won’t do anything I assume this is just so batched commands can be used as a drop in replacement for a single Cmd msg value anywhere in your codebase?
It feels a little odd because it’s the equivalent of returning void/Unit/your language's equivalent and executing the provided Cmds for their side-effects but I realise we’re in the Platform part of Elm here so side-effects are expected.
I followed the source code through to the kernel which wasn’t hugely illuminating after the type signature and limited documentation left me scratching my head. I’d be very interested to hear more about how it works!
If I’ve correctly inferred its behaviour, is this something that might be clarified in the documentation? There is an example but the reductive Cmd.none usage means it doesn’t tell us how batch behaves outside the trivial case.
It returns a new command, that behind the scenes executes all of the commands in the list in one go. It’s not possible to re-implement this function on your own using other functions, because it is too low-level. Here’s the definition:
Right above that, you can see that Cmd.none is implemented as Cmd.batch [].
The Kernel stuff means that the function is implemented in JavaScript (which the lowest level core functions have to be – you gotta start somewhere, right?)
‘some side-effect I want Elm to perform, which, depending on what it does, might at some point send one of the instances of msg back to my application using a Sub msg’
Cmd.batch does not return ‘one of the elements of the list’ (as you deduce yourself, this is impossible), and does not return Cmd.none (as this would mean no effects ever happen), but rather it uses the special properties that a (Cmd x) has, to ‘combine them all into one’.
This ‘special combining property’ is the property that the Elm runtime system is able to run all of them in some (unspecified) order for you. So no: It does not construct a Cmd.none, but builds an internal datatype that you cannot build yourself directly.
And lo and behold, there also is a Sub.batch, which works the same way (but the other way around: Allowing you to subscribe to messages coming from multiple different places).
If we were talking about elements that do not have such a special property, like a function List a -> a, then we have a problem: This function cannot exist, because there is no way to ‘pluck an a out of thin air’ in the empty-list case.
As @lydell already noted, it is impossible to alter this stuff inside of Elm, because it is part of the low-level JS code that Elm is made up of.
I think the core misconception here is that commands represent a single side effect. This is incorrect.
These are not the only possibilities.
Because a single command can represent zero or more side effects, batch can take a lot of commands and combo them all into a single one that does all the side effects. @Sebastian and @gampleman have shown different models that would allow valid implementations of batch : List (Cmd a) -> Cmd a that still preserve all the given side effects.
Personally, I find it helpful to think of Cmd.batch as a sort of “squash” or “flatten”. I also find it helpful to imagine Cmd a as representing a list of side effects, rather than a single effect