Cmd.batch return value

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:

  1. return a none value of type Cmd msg (e.g. Platform.none)
  2. 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.

Thanks very much!

I havn’t used that yet, but my guess is that is creates and returns a new command which goes through the given list and performs each command there.

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?)

The Cmd msg type is meant to indicate

‘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.

1 Like

If were to model this in pure Elm, I will have an opaque list, something like:

type Cmd = Cmd (List SideEffect)

SideEffect here is actual command to perform. We never have access to this type.

Commands

Anything that returns a command will return

Cmd [ sideEffect ] 

Cmd.none

Cmd.none would return Cmd []

Cmd.batch

Cmd.batch flattens whatever is given e.g.

Cmd.batch [ Cmd [], Cmd [ sideEffect ] ] ==> Cmd [ sideEffect ]

I don’t know if this the actual implementation, but this helps me to have a model in my head of how Cmd could possibly work.

2 Likes

It could even be like this recursive definition:

type Cmd msg 
     = CurrentTime msg
     | SendHTTP HTTPRequest msg
     | ...
     | None 
     | Batch (List (Cmd msg))
1 Like

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 :slightly_smiling_face:

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