elmelm-architecture

What is the meaning of `Cmd msg`?


I'm trying to use ports to pass an URL to Javascript in order to redirect the user to another page. I wrote a port module to contain all the ports needed for my project :

port module Utils exposing (..)
port changePage : String -> Cmd Event

Then, I imported it in my Elm file :

type Event = PageChange String
import Utils exposing (changePage)

But the compiler didn't like it :

It looks like the keyword `import` is being used as a variable.
8| import Utils exposing (changePage)
         ^
Rename it to something else.

So I moved the port definition to the main file :

type Event = PageChange String
port changePage : String -> Cmd Event

But the compiler still didn't agree :

Port `changePage` has an invalid type.
28| port changePage : String -> Cmd Event
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You are saying it should be:
 String -> Platform.Cmd.Cmd BmC.Index.Event
But you need to use the particular format described here:
<http://guide.elm-lang.org/interop/javascript.html#ports>

So I went to see that particular format, port check : String -> Cmd msg. I didn't understand where that msg came from, so I went to check the code, and I still don't understand what that line means.

Where does msg come from? What does type Cmd msg = Cmd mean? Thanks in advance.


Solution

  • import statements have to come before any function or type definitions. That's the reason you got a compile error on this code:

    type Event = PageChange String
    import Utils exposing (changePage)
    

    On your questions of ports: Elm's ports are a feature that are on the edge of the architecture. They allow for interop with a different language, so there is, for all intents and purposes, a little magic going on behind the scenes.

    Other languages have similar "magical" constructs for interop with other languages. Haskell has Foreign Function Interface (FFI) and C# has the extern keyword to call external libraries.

    The definition of Cmd is one of those pieces that doesn't really make sense by looking at the code.

    type Cmd msg = Cmd
    

    That doesn't really tell us much, but that's ok. It's more of a placeholder that the compiler fills in on compile time. Other languages do that too. Haskell often uses a bottom call of let x = x in x to signify a function that the compiler will actually implement.

    So, unless you're truly interested in the implementation of that crossover between Elm and Javascript, it's ok it leave it to the imagination and accept the magic.

    As for being able to specify a concrete type in your port, that's just another choice of the compiler team. Even though a Cmd Event is the only thing that could go through the port, they chose to force a generic type as the Cmd's type parameter. The exact spelling of Cmd msg isn't required. msg could be anything lowercase:

    port check : String -> Cmd a