What's the point of Process.spawn?

I know the docs for Process state explicitly that it’s an early concept and will likely evolve. Specifically, processes cannot receive messages. However, it also seems they cannot send messages (well, more than once). I wrote this as a little sample

after1Sec : Int -> Task.Task x ( Process.Id, Int )
after1Sec i =
    Process.sleep 1000
        |> Task.andThen
            (\() ->
                Process.spawn (after1Sec (i + 1))
                    |> Task.andThen
                        (\id ->
                            let
                                _ =
                                    Debug.log "id" id

                                _ =
                                    Debug.log "i" i
                            in
                            Task.succeed ( id, i )
                        )
            )

If I run this with Task.perform GotIdAndInt (after1Sec 0), the first Process.Id will be returned along with 0. If I inspect the console, I see that the it continues to print. However it seems that not only is a process not able to receive messages, it effectively can’t send them either. In a functional language, a process that can’t receive or send data can’t do anything (outside of our Debug escape hatches).

I’m just exploring here. I know about Time.every, I’m more curious as to whether this can truly do nothing or if I’m missing something here.

The docs talk about invoking multiple HTTP requests. I haven’t tried that particular case, but in any case, it doesn’t seem like you’d be able to get any data back from it.

1 Like

As is Process.spawn is completely useless. There isn’t really any practical use for it.

4 Likes

It’s used a bit internally in elm/* packages:

❯ rg 'Process.spawn|_Scheduler_spawn' --sort path
browser/src/Browser/AnimationManager.elm
77:            Process.spawn (Task.andThen (Platform.sendToSelf router) rAF)
99:    Process.spawn (Task.andThen (Platform.sendToSelf router) rAF)

browser/src/Elm/Kernel/Browser.js
399:	return __Scheduler_spawn(__Scheduler_binding(function(callback)

browser/src/Elm/Kernel/Browser.server.js
33:var _Browser_on = F4(function() { return __Scheduler_spawn(_Browser_unitTask); });

core/src/Elm/Kernel/Scheduler.js
81:function _Scheduler_spawn(task)

http/src/Http.elm
1016:          Process.spawn (Elm.Kernel.Http.toTask router (Platform.sendToApp router) req)

time/src/Time.elm
505:          Process.spawn (setInterval interval (Platform.sendToSelf router interval))

(Process.spawn is called _Scheduler_spawn in the JavaScript Kernel code.)

I couldn’t tell you exactly what it does, because I always quickly get lost in the scheduler code.

4 Likes

Interesting. I gather now that it’s meant for effect managers, which are (AFAIK) not officially documented anywhere. Interesting, if you declare an invalid effect module Main you get

This type of module is reserved for the @elm organization. It is used to define certain effects, avoiding building them into the compiler.

But if you add a little more effect module Main where { subscription = MySub } you get

Note: Effect modules are designed to allow certain core functionality to be defined separately from the compiler. So the @elm organization has access to this so that certain changes, extensions, and fixes can be introduced without needing to release new Elm binaries. For example, we want to make it possible to test effects, but this may require changes to the design of effect modules. By only having them defined in the @elm organization, that kind of design work can proceed much more smoothly.

From a language design standpoint, I totally get it, but I really wish Elm let you “tinker”, like Rust: the default language is safe but allows some escape hatches if you want to try something out or learn how you could code some of the base library stuff (like “smart pointers”).

That’s different, IMO, from supporting something like FFI or “impure” functions - a decision I completely agree with. Allowing those is a significant design change that would remove guarantees the language. This is something that is currently built into the language but just isn’t allowable for mere mortals.

The language allows ports, but not in packages, for example.

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