Stream: platform development

Topic: Can a platform require and provide more then one synbol?


view this post on Zulip Oskar Hahn (Nov 26 2023 at 12:14):

When I was trying to write a simple platform for AoC, my first idea was to provide two functions to the platform. One for part1 and another for part2. For example:

platform "aoc"
    requires {} {
        part1 : Str,
        part2 : Str,
    }
    exposes []
    packages {}
    imports []
    provides [
        part1ForHost,
        part2ForHost,
    ]

part1ForHost : Str
part1ForHost = part1

part2ForHost : Str
part2ForHost = part2

But it seems, that it is neigher possible to require two symbols, nor provide two symbols to the zig-part.

Two requires is a Parse error:

Parse error was:

Header(Requires(ListStart(@68), @14))

I found this example in the roc repo, where an app provides more then one function, but I could not find the corresponding platform. So maybe it is possible, but I am using the wrong syntax?

https://github.com/roc-lang/roc/blob/main/crates/compiler/load_internal/tests/fixtures/build/app_with_deps/Quicksort.roc

For the second part, it seems, that only the first symbol is exported to the linker:

platform "aoc"
    requires {} { solution : (Str, Str) }
    exposes []
    packages {}
    imports []
    provides [
        solutionForHost,
        solution2ForHost,
    ]

solutionForHost : (Str, Str)
solutionForHost = solution

solution2ForHost : (Str, Str)
solution2ForHost = solution
── UNUSED DEFINITION ─────────────────────────────── days/../platform/main.roc ─

solution2ForHost is not used anywhere in your code.

15│  solution2ForHost = solution
     ^^^^^^^^^^^^^^^^

If you didn't intend on using solution2ForHost then remove it so
future readers of your code don't wonder why it is there.

────────────────────────────────────────────────────────────────────────────────

An internal compiler expectation was broken.
This is definitely a compiler bug.
Please file an issue here: https://github.com/roc-lang/roc/issues/new/choose
thread '<unnamed>' panicked at 'Error:
    Failed to rebuild host.zig:
        The executed command was:
            zig build-exe -fPIE -rdynamic days/../platform/libapp.so /tmp/host_bitcodeeuGxgAj3.o days/../platform/host.zig -femit-bin=days/../platform/dynhost --mod glue::/home/ossi/src/roc/crates/compiler/builtins/bitcode/src/glue.zig --deps glue -lc -target native -fcompiler-rt
        stderr of that command:
            error: ld.lld: undefined symbol: roc__solution2ForHost_1_exposed_generic
    note: referenced by host.zig:21
    note:               days/../platform/dynhost.o:(host.main)
    note: did you mean: roc__solutionForHost_1_exposed_generic
    note: defined in: days/../platform/libapp.so
', crates/compiler/build/src/link.rs:1414:21
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at 'Failed to (re)build platform.: Any { .. }', crates/compiler/build/src/program.rs:1021:46

Is this something, that is in the scope of roc, or should there be only one exported symbol?

view this post on Zulip Richard Feldman (Nov 26 2023 at 12:48):

it definitely should be supported, it's just not implemented yet :big_smile:

view this post on Zulip Brendan Hansknecht (Nov 26 2023 at 15:39):

Yeah, currently the only way to make that work is to return a record of functions to main, but that is a bit jank.

view this post on Zulip Brendan Hansknecht (Nov 26 2023 at 15:41):

Also, pretty sure that the "app" you found is just a test for parsing and loading into the AST. So we have the parsing for this, but we haven't wired it all the way through.

view this post on Zulip Brendan Hansknecht (Nov 26 2023 at 15:41):

Definitely a missing feature that needs to be implemented.

view this post on Zulip Oskar Hahn (Nov 27 2023 at 14:01):

The easiest way for the moment (when both function should return the same type) is to use an argument. The following works perfectly:

platform "aoc"
    requires {} { solution : [Part1, Part2] -> Str }
    exposes []
    packages {}
    imports []
    provides [solutionForHost]

solutionForHost : [Part1, Part2] -> Str
solutionForHost = \part ->
    when part is
        Part1 -> solution Part1
        Part2 -> solution Part2

view this post on Zulip Brendan Hansknecht (Nov 27 2023 at 16:33):

I really thought something like this would work, but apparently, roc is missing some sort of type understanding for this to work as well:

platform "aoc"
    requires {} { solution : { part1 : {} -> Str, part2 : {} -> Str } }
    exposes []
    packages {}
    imports []
    provides [solutionForHost]

solutionForHost : [Part1, Part2] -> Str
solutionForHost = \part ->
    when part is
        Part1 ->
            solution.part1 {}
        Part2 ->
            solution.part2 {}

view this post on Zulip Oskar Hahn (Nov 27 2023 at 17:18):

It works for me. I copied and pasted your suggestion and adapted the app. I am not sure yet, which solution I like better:

https://github.com/ostcar/aoc2023/blob/return_two_functions/platform/main.roc

view this post on Zulip Brendan Hansknecht (Nov 27 2023 at 17:35):

interesting, wouldn't roc check for me, maybe I messed something else up.

view this post on Zulip Oskar Hahn (Nov 29 2023 at 16:29):

I added an issue for this: https://github.com/roc-lang/roc/issues/6115

view this post on Zulip Brendan Hansknecht (Nov 29 2023 at 16:43):

Thanks!


Last updated: Jul 06 2025 at 12:14 UTC