I think about commands as anything you can ask the Elm runtime. Tasks is a subset of there where failure (mostly) is an option.
I don’t mean to change the subject, but I think tasks without error could probably be commands instead, so tasks could be all about dealing with errors!
Task is not all about dealing with errors. Task has to be converted to Cmd to be executed by the Elm Runtime, and the execution of the Cmd may cause errors.
Our Elm code world is pure, so all the side effects are dealt by the Elm Runtime. Cmd Msg is data itself, when it is passed to the Runtime, it is like saying
“hey Runtime, can You do this for me, when it’s done, pass back the Msg.”
Whilst task is living in the Elm world, it is data too, it is like saying
’ I plan to do the follow things’
It is only when it is passed to Task.perform or Task.attempt as an argument that it is converted to Cmd and thus be executed by Elm runtime.
Tasks can be chained together, so it is very useful when you need a list of Cmd to be executed in sequential order.
This is not a silly question. This topic can be quite tricky.
Tasks are guaranteed to complete. Cmds are not guaranteed to complete.
If you think in terms of message passing, Tasks are like a request-response synchronous type of communication while Cmds are asynchronous messages.
If you call to JS through a port, expect a reply and forget to send the reply from JS, you might have something like a “leak”. You can mitigate that by introducing a timeout but the decision was made that it would be best to keep the communication with JS asynchronous.
I know that this is where elm philosophically draws a line, but I find it really rather arbitrary. Tasks can’t really be guaranteed to complete unless the program is guaranteed to execute for an arbitrary amount of time. Also, there’s no guarantees built into the language about the guaranteed completion of tasks, so you still have to write your program as if you could get the resulting message 0 or many times.