Stream: beginners

Topic: Platform basics


view this post on Zulip Michal Timko (Sep 05 2024 at 06:45):

Hello,
I am coming from nodes/js/ts environment and just stumble upon Roc.

I am sorry for being stupid, but I somehow cannot wrap my head about the relationship between core Roc lang and platform. How is it comparable to other languages where you typically have the lang itself, some standard library and various frameworks on top of that?

Also as I understand from few posts, Roc on its own cannot handle IO and is reliant on platform. Isn't it quite limiting to not have such important feature in the basic package? Is there some strong reason to have it this way?

view this post on Zulip Luke Boswell (Sep 05 2024 at 07:00):

G'day @Michal Timko , welcome :wave:

Have you seen this guide? https://www.roc-lang.org/platforms

view this post on Zulip Michal Timko (Sep 05 2024 at 07:10):

I read through that.
It looks like platform is something like both external library and interface between Roc and another lang, that actually compile some executable from the code.

But the it raise another questions like if it doesn't make Roc just nice interface for Rust and what is possible to do with Roc without platform (can I even compile it to executable without platform?)

So for me is unclear what type of entity the platform is and what I can expect from it. But maybe when i try to build something, it will start making sense.

view this post on Zulip Luke Boswell (Sep 05 2024 at 07:12):

Yeah, I definitely recommend you try roc out. Maybe checkout the basic-cli and basic-webserver first. You could then also look at roc-wasm4 (a game platform), or one of the others.

view this post on Zulip Michal Timko (Sep 05 2024 at 07:17):

My background is web developer, so my first intuition is "how to build server with this?"
And when I read a bit about platforms and the IO limitations, second question was "Can I build https server with this, if I need both web based api and IO in one platform?"

So I will see, what I can do.

view this post on Zulip Sam Mohr (Sep 05 2024 at 07:29):

@Michal Timko I think Roc's platforms make more explicit the relationship we have to lower level languages. The reason we use JS to write webservers is because we don't want to think about how to do stuff like manage memory or access resources, we want a PL that has done that adequately for us.

view this post on Zulip Sam Mohr (Sep 05 2024 at 07:30):

Roc functions as a language that is easy to write in and think about, and actively talks to someone else for the important stuff. But I'd rather write my logic in an easy language like Roc and have Rust do the hard stuff that needs to be done particularly and efficiently

view this post on Zulip Sam Mohr (Sep 05 2024 at 07:31):

JS doesn't go quite as far, but there are a lot of "performance critical" libs written in C that get wrapped in JS. Platforms work a similar way to that FFI

view this post on Zulip Luke Boswell (Sep 05 2024 at 07:44):

Shameless plug for my demo app https://github.com/lukewilliamboswell/roc-htmx-tailwindcss-demo

view this post on Zulip Luke Boswell (Sep 05 2024 at 07:44):

If you're coming from a web background, and looking for something to hack around with... you're welcome to play with that and if you want to make a PR with any features I'd be happy to review.

view this post on Zulip Luke Boswell (Sep 05 2024 at 07:45):

The goal of that demo is to be a good starting point for building web apps with roc, and demonstrate how to use familiar technologies like htmx and tailwindcss.

There's a lot more we could add in there, I just get distracted easily with other things :smiley:

view this post on Zulip Michal Timko (Sep 05 2024 at 07:46):

Thank you,
will look into it.

view this post on Zulip Anton (Sep 06 2024 at 05:22):

Can I build https server with this, if I need both web based api and IO in one platform?

basic-webserver has both, it support for example File.write, Stdout.line and Http.get, ...

view this post on Zulip Michal Timko (Sep 06 2024 at 06:19):

Yeah...I already realize it too. It just that in one speech Feldman mention something along the line that you probably don't need IO for web based apps, so I just assume that web oriented platforms are without IO...silly me.

view this post on Zulip Rick Hull (Jan 14 2026 at 21:27):

I am writing a basic platform that calls into libsecp256k1 to do some crypto stuff. I have a platform/host.c with some LLM help. it seems like there is a naming convention like roc_fx_blah that allows calling C functions from Roc. is this documented?

view this post on Zulip Rick Hull (Jan 14 2026 at 21:52):

Tell me where I'm wrong: in modern platform Roc, i would create a function signature, within a module, named with an exclamation mark. this means impure (does it directly imply it's a host-implemented function?). all calls into the host are impure. if roc sees this with no def, it will construct a symbol based on the function name, and try to call that symbol. If I had module Rick, function hull!, then roc constructs roc_fx_rickHull (note the casing and lack of underscores) and I would need to have this defined in my host.c

view this post on Zulip nandi (Jan 14 2026 at 22:15):

i ran glm on codebase and this is what it said:

There's a Zig-based platform in test-platform-effects-zig/host.zig. Looking at the code, the function naming follows
the same convention:

The naming convention is:
• Strip the ! from the Roc function name
• Prefix with roc_fx_
• No CamelCase conversion - underscores stay as-is

Examples from the Zig host:

zig
pub export fn roc_fx_get_line() str.RocStr { ... }
pub export fn roc_fx_put_line(rocPath: *str.RocStr) i64 { ... }
pub export fn roc_fx_get_int() GetInt { ... }
pub export fn roc_fx_id_effectful(input_num: u64) u64 { ... }

So if you had a Roc module with Rick.hull!, the Zig host would define:

zig
pub export fn roc_fx_hull(...) {
// your implementation
}

The key points:

1. ! suffix = impure function (side effects)
2. roc_fx_ prefix = foreign function that Roc calls
3. No casing conversion - original identifier name is preserved
4. Must be marked pub export in Zig to be callable from Roc

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:15):

The calling convention is documented in https://github.com/roc-lang/roc/blob/2ca9919d86d429751149bd8877e57e9ecbc7243f/src/builtins/host_abi.zig

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:16):

A type module with an annotation only definition is a "hosted effect".

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:17):

Ah... are you talking about the new compiler or the old rust one?

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:17):

They're quite different

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:19):

Host calling into Roc -- these are the entrypoints which are defined in the platform header "provides" section

Roc calling back into Host -- these are the hosted effects, i.e. functions without definition like hull! : Str => {}

view this post on Zulip Rick Hull (Jan 14 2026 at 22:41):

Thanks, this is helpful! so the module name is no longer included? I suppose I am asking about hosted effects. also, I am currently using C and gcc on the host side. i haven't actually installed roc yet, heh

view this post on Zulip Rick Hull (Jan 14 2026 at 22:43):

https://gist.github.com/rickhull/e4ae108e4f00de5582f37689146003c0 how does this look?

view this post on Zulip Rick Hull (Jan 14 2026 at 22:50):

also, where does the zig (rust?) for basic-cli live? i was looking for e.g. platform/host.zig is that an old convention?

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:52):

The basic-cli platform is still in the process of being migrated to the new compiler, you can see the work here https://github.com/roc-lang/basic-cli/pull/413

My roc-platform-template-zig and roc-platform-template-rust are both already upgraded to the new compiler.

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:54):

Yes the module keyword has been deprecated. We now use "type modules" which are centered around a single nominal type with associated functions, like

Sqlite := [].{
    ...
}

view this post on Zulip Luke Boswell (Jan 14 2026 at 22:55):

All of your syntax is for the old rust compiler... are you wanting to write a platform for that or the new compiler?

view this post on Zulip nandi (Jan 14 2026 at 22:58):

the new compiler is more fun, join us :rolling_on_the_floor_laughing:

view this post on Zulip Rick Hull (Jan 15 2026 at 03:19):

I think I should probably keep it simple and use whatever is most documented. i might then migrate to the new compiler. it won't be much code

view this post on Zulip Luke Boswell (Jan 15 2026 at 03:42):

I'd recommend the new compiler, it's a much more sane experience for platform authors.

view this post on Zulip Rick Hull (Jan 15 2026 at 05:53):

what are some good approaches for length validation? for example, a 32 byte SHA256 result. my current understanding is this would commonly be represented as List U8. I have come up with a way to make a Digest type that does some length validation. basically an opaque type, accompanied by a constructor function that does the validation.

view this post on Zulip Luke Boswell (Jan 15 2026 at 05:56):

If I wanted to guarantee something was a fixed size, I would use a nominal record

SHA256 :: {
    field1: U8,
    field2: U8,
    field3: U8,
    field4: U8,
    field5: U8,
    ....
}.{
    ## put methods here to work with etc
}

view this post on Zulip Luke Boswell (Jan 15 2026 at 05:59):

Another advantage of this over a list is that it isn't refcounted

view this post on Zulip Rick Hull (Jan 15 2026 at 05:59):

hmmm, i would never want to address the individual fields. but this is interesting.

view this post on Zulip Rick Hull (Jan 15 2026 at 06:01):

i am calling into libsecp256k1; is it sensible to stick with C, or should I try Zig? I am a bad C programmer ;)

view this post on Zulip nandi (Jan 15 2026 at 06:03):

zig zig zig

view this post on Zulip Rick Hull (Jan 16 2026 at 03:53):

@Luke Boswell can I strongly request that your platform templates be added to: https://www.roc-lang.org/platforms where it says:

Anyone can implement their own platform. There isn't yet an official guide about how to do this, so the best way to get help if you'd like to create a platform is to say hi in the #beginners channel on Roc Zulip!

view this post on Zulip Anton (Jan 16 2026 at 09:29):

I will improve the docs there

view this post on Zulip Anton (Jan 16 2026 at 09:35):

https://github.com/roc-lang/www.roc-lang.org/pull/46

view this post on Zulip Rick Hull (Jan 16 2026 at 14:24):

I am still working on my libsecp256k1 platform, but I started from roc-platform-template-zig this time, and I'm using the latest nightly compiler. however, I am getting a lot of weird errors that don't agree with the tutorial or stdlib. e.g.

Error: Exit code 1
roc hello_world.roc
-- DOES NOT EXIST --------------------------------

 Num.to_str does not exist.

    ┌─ hello_world.roc:19:36
    │
 19 │     Stdout.line!("pubkey length: ${Num.to_str(len)}")
    │                                    ^^^^^^^^^^

view this post on Zulip Rick Hull (Jan 16 2026 at 14:44):

https://gist.github.com/rickhull/7e3c2468f2327853d29b00391824cf63 why might this be happening?

view this post on Zulip Anton (Jan 16 2026 at 14:49):

The tutorial and stdlib docs are for roc alpha 4, for the new nightlies you can look at:

view this post on Zulip Rick Hull (Jan 16 2026 at 14:53):

I see -- and this implied by the redirect URL. now, it looks like I have roc-src on one commit (from Jan 1) but my compiler is from Jan 15. going to fix this and retry with the proper builtin calls

view this post on Zulip Anton (Jan 16 2026 at 14:56):

If you are using the nightly compiler from https://github.com/roc-lang/nightlies/releases you probably do not need roc-src as well

view this post on Zulip Anton (Jan 16 2026 at 14:57):

I think Luke used roc-src for easy debugging

view this post on Zulip Rick Hull (Jan 16 2026 at 15:02):

to what extent is the tutorial specific to alpha-4? is it just the builtin calls or is it more subtle?

view this post on Zulip Anton (Jan 16 2026 at 15:14):

It's quite broad, alpha4 has different syntax, different features, different builtins. For a quick comparison between alpha4 and the new compiler(=nightlies) you can check https://github.com/roc-lang/roc/blob/main/test/fx/all_syntax_test.roc vs https://github.com/roc-lang/examples/blob/main/examples/AllSyntax/main.roc (alpha4)

view this post on Zulip Rick Hull (Jan 16 2026 at 18:17):

What do we think about possibly adopting Just (justfile) instead of shell scripts? I have only just started using it (heh), and I've found it fantastically easy and helpful. for example, instead of roc-platform-template-zig/bundle.sh there would be a just bundle task. instead of ci/all_test.sh, just ci
I understand that it's not desirable to force tooling like this on users, but it seems like a nicer fit for my own projects

view this post on Zulip Anton (Jan 16 2026 at 18:37):

Just does not come pre-installed on github CI, that's already adding more friction than I would like. Also, I would like to convert the sh scripts to Roc scripts once basic-cli is ported for the new compiler and works well enough. Roc does not come pre-installed on CI but it's good to test our own stuff in the real world :)

view this post on Zulip Rick Hull (Jan 16 2026 at 18:39):

good to know. i see that Just also executes each line in its own shell environment, so complex scripts are not suited. I haven't looked at build.roc but I have come across it. and I am also using build.zig.zon so, many things overlap. what is the story with build.roc ?

view this post on Zulip Rick Hull (Jan 16 2026 at 18:40):

isn't there some way to specify some existing tools in the GH CI environment, like in a cached image or something?

view this post on Zulip Anton (Jan 16 2026 at 18:46):

what is the story with build.roc ?

build.roc should be in charge of building the platform. old Roc did not work well on windows so you may see e.g. .sh files instead.

view this post on Zulip Rick Hull (Jan 16 2026 at 18:47):

what about testing conventions? I am vaguely aware of the expect keyword. in my case, I am working on a platform first, so my question is maybe oriented around platforms. i am tempted to make e.g. test/host.roc to test functions in the Host module. I have also seen examples/test.roc

view this post on Zulip Anton (Jan 16 2026 at 18:48):

isn't there some way to specify some existing tools in the GH CI environment, like in a cached image or something?

github cache space is precious with only 10 GB which is easily filled with all the different systems we have to support.

view this post on Zulip Rick Hull (Jan 16 2026 at 18:50):

i know this is a bad idea, but I wonder if we should use a different forge as the central repo, or even run our own. and mirror to GH. I can imagine it just adds operational headache and expense

view this post on Zulip Anton (Jan 16 2026 at 18:52):

Rick Hull said:

what about testing conventions? I am vaguely aware of the expect keyword. in my case, I am working on a platform first, so my question is maybe oriented around platforms. i am tempted to make e.g. test/host.roc to test functions in the Host module. I have also seen examples/test.roc

For end-to-end integration tests I typically use expect: https://github.com/roc-lang/basic-cli/blob/main/ci/expect_scripts/bytes-stdin-stdout.exp . I also want to replace that with Roc when possible though.

Example for unit tests: https://github.com/roc-lang/basic-cli/blob/b5bc8ba9435633cd4aeea28d116127eeaea818d2/platform/Url.roc#L513

view this post on Zulip Anton (Jan 16 2026 at 18:55):

Rick Hull said:

i know this is a bad idea, but I wonder if we should use a different forge as the central repo, or even run our own. and mirror to GH. I can imagine it just adds operational headache and expense

It's hard to beat free CI :smile:

view this post on Zulip Rick Hull (Jan 16 2026 at 18:56):

for my use case: I have just nuke, just clean, just build, etc. i am trying to support an edit-build-test cycle. i currently have a just run, which just does something like roc hello_world.roc or roc main.roc.

so then I have some workflow tasks: just dev (build + run), just fresh (clean + dev). just nuke wipes all cache and is invoked on its own. i think just run is actually a bad idea and I really want just test. this would run "unit tests" that are roughly analogous to smoke tests, doing slightly more than hello world to show the build was successful

view this post on Zulip Rick Hull (Jan 16 2026 at 18:57):

test/host.roc, test/sha256.roc, test/sign.roc something like that

view this post on Zulip Anton (Jan 16 2026 at 18:59):

I like simple commands too, I have it set up with nix:

roc/src on  zig-compiler-benchmarks
❯ nix develop
Restored session: Fri Jan 16 19:58:49 CET 2026
Some convenient commands:
  buildcmd =   zig build roc
  testcmd =   zig build snapshot && zig build test
  fmtcmd =   zig build fmt
  covcmd =   zig build coverage
  cicmd =   zig build fmt && ./ci/zig_lints.sh && zig build && zig build snapshot && zig build test && zig build test-playground && zig build coverage
$

view this post on Zulip Rick Hull (Jan 16 2026 at 19:00):

I used to run nixos and have used nix in anger, but I emphasize anger. it never clicked for me. but I think there could be some really cool synergy / symmetry with its immutable nature and use in build environments

view this post on Zulip Rick Hull (Jan 16 2026 at 19:02):

so it looks like you are really leaning on the zig runner (?) in a way that I'm not. maybe that's a natural direction to go in

view this post on Zulip Anton (Jan 16 2026 at 19:03):

so it looks like you are really leaning on the zig runner (?)

Yes for the main repo, a ton is in build.zig. It has been working well for us.

view this post on Zulip Rick Hull (Jan 16 2026 at 19:04):

I am brand new to Zig, Roc, and platforms. nearly all of my direct experience is with scripts against runtimes (shell, ruby, elixir, etc). but I've long had an itch for gradual-strong typing (to enforce correctness without being a huge PITA) and deployable artifacts (no runtime)
I guess what I'm getting at is that I started with roc-alpha-4 and C, so I needed a Makefile (ugh!). then I adopted Just (yay!). but now that I'm basing my host on Zig, there is a world of Zig tooling that I'm totally unaware of, analogous but not exactly comparable to the C ecosystem (a good thing!)

view this post on Zulip Anton (Jan 16 2026 at 19:06):

I'm signing off for today :wave: but others should be available for additional questions :)

view this post on Zulip nandi (Jan 16 2026 at 20:57):

Anton said:

so it looks like you are really leaning on the zig runner (?)

Yes for the main repo, a ton is in build.zig. It has been working well for us.

I use zig build system for every language lol zig4lyfe

view this post on Zulip nandi (Jan 16 2026 at 20:59):

Rick Hull said:

I used to run nixos and have used nix in anger, but I emphasize anger. it never clicked for me. but I think there could be some really cool synergy / symmetry with its immutable nature and use in build environments

I have such a like/dislike relationship with nix. On the one hand it think it's conceptually kinda cool. On the other hand, I've usually been able to do something similar much simpler

view this post on Zulip nandi (Jan 16 2026 at 21:02):

Rick Hull said:

I am brand new to Zig, Roc, and platforms. nearly all of my direct experience is with scripts against runtimes (shell, ruby, elixir, etc). but I've long had an itch for gradual-strong typing (to enforce correctness without being a huge PITA) and deployable artifacts (no runtime)
I guess what I'm getting at is that I started with roc-alpha-4 and C, so I needed a Makefile (ugh!). then I adopted Just (yay!). but now that I'm basing my host on Zig, there is a world of Zig tooling that I'm totally unaware of, analogous but not exactly comparable to the C ecosystem (a good thing!)

I was building a zig/rust hybrid project the other day, this is a section of my zig build file

    // =========================================================================
    // Step 1: Build Rust Library
    // =========================================================================
    const cargo_build = b.addSystemCommand(&[_][]const u8{
        "cargo",
        "build",
        "--release",
        "--lib",
        "--features",
        "gtk",
    });
    cargo_build.cwd = b.path(".");

view this post on Zulip Luke Boswell (Jan 17 2026 at 01:21):

Anton said:

Just does not come pre-installed on github CI, that's already adding more friction than I would like. Also, I would like to convert the sh scripts to Roc scripts once basic-cli is ported for the new compiler and works well enough. Roc does not come pre-installed on CI but it's good to test our own stuff in the real world :)

Yeah -- basic cli was such a nice cross-platform scripting setup. We'll be back there soon :smiley:

view this post on Zulip Dan G Knutson (Jan 17 2026 at 01:58):

a /scripts dir full of .roc files would let you claim to be partially self-hosted

view this post on Zulip Rick Hull (Jan 17 2026 at 03:36):

I ran into a very confusing issue where my platform/host.zig has hosted_function_ptrs with a specific order, and when I removed some modules from my exposes in platform/main.roc for troubleshooting, the wrong functions were being called. this coupling seems difficult to validate and troubleshoot. have people run into this before?

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:37):

The hosted functions are those exposed by the platform... so this makes sense in that it's the platform authors responsibility to ensure the function pointers are in the correct order.

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:38):

This statement probably doesn't help you much though. I think you and I may be the only people who have written a platform in the new compiler @Rick Hull :smiley:

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:39):

The order is alphabetical based on fully qualified name if I recall.

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:40):

I'd like to mention also... that the intended design for platform authors is to use roc glue instead of rolling all these manually. We are just in that awkward place in time where the glue subcommand isn't implemented yet for the new compiler so it's all manual

view this post on Zulip Rick Hull (Jan 17 2026 at 03:40):

All quite sensible, thanks!

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:41):

roc glue path/to/generate_c_platform.roc path/to/my/platform/main.roc or something like that and it scaffolds out literally everything you need with a nice type safe (maybe not in C :sweat_smile: ) implementation.

view this post on Zulip Rick Hull (Jan 17 2026 at 03:42):

i'm so happy with the zig template and the zig DX, compared to trying make a platform from scratch in C as my "hello world" LOL. i don't mind a little less magic at this stage.

I literally could not have done it without extensive help from Claude code (z.ai models, cheaper) and a little bit of Gemini CLI (free)

view this post on Zulip Luke Boswell (Jan 17 2026 at 03:59):

On of the assumptions we have for the future is that platforms will be abundant and should be easy to fork and modify to meet individual needs. It's good to know that LLM's can help with that and the tools should only make that even easier I think. :smiley:

view this post on Zulip Dan G Knutson (Jan 17 2026 at 14:29):

re: justfile, one thing I do sometimes is add one for just myself (like a script for installing), and then put it in .git/info/exclude. In the case of the roc repo, they already ignore extra files with no extensions, so you just need to be careful to not delete it. I think just also has some walk-up-the-tree feature that would let you keep your personal scripts for a repo outside the repo (or you could symlink it)

view this post on Zulip Rick Hull (Jan 17 2026 at 23:18):

the way I have decided to structure my project for now, is I have examples/ and test/; I have test/host.roc and test/host.zig, targeting platform/Host.roc and platform/host.zig respectively. I can use the roc and zig test runners, but I am using Just as "my metalayer" to tie everything together and support "complex workflows" like edit-build-test (heh)

for a scripts-on-runtime-person, i am used to executing things immediately, and i don't automatically know to e.g. zig build test but Just helps me with that

view this post on Zulip Rick Hull (Jan 17 2026 at 23:25):

also, I think zig has a feature, or is this roc?, where you put the tests in the implementation file, at the toplevel. maybe I should use that more?

view this post on Zulip Rick Hull (Jan 18 2026 at 03:33):

to answer my question, zig supports inline tests at the toplevel, but these have a restricted "scope" -- they should be used like unit tests for pure-ish functions defined within the file.

roc supports inline tests at the toplevel, what I am calling comptime tests. these use the expect keyword invoked by roc test. or you can make a "test script" that calls expect within a main function. these are runtime tests invoked by roc.

Is this accurate?

view this post on Zulip Rick Hull (Jan 18 2026 at 04:32):

Separately, all host functions are impure by definition, and pure functions cannot call impure functions. so if my application is purely functional, then I cannot call any platform functions?

I know I have a misunderstanding somewhere, just not sure where

view this post on Zulip Luke Boswell (Jan 18 2026 at 04:36):

expect at the top level is a unit test - these are run with roc test
expect within an expression (like a block expression) is an assertion - these throw a runtime error if not true.

view this post on Zulip Rick Hull (Jan 18 2026 at 04:52):

this confirms, but gives me better language. unit test vs assertion

view this post on Zulip Richard Feldman (Jan 18 2026 at 05:41):

important detail: unlike assertions, expect never stops execution

view this post on Zulip Richard Feldman (Jan 18 2026 at 05:42):

it will cause a test to fail, and it will report an error, but program execution always continues normally no matter what happens with them

view this post on Zulip Luke Boswell (Jan 18 2026 at 05:43):

The platform host has a special handler it provides Roc roc_expect_failed or similar which is called when these fail right?

view this post on Zulip Luke Boswell (Jan 18 2026 at 05:44):

So the platform author is responsible for deciding what to do with that

view this post on Zulip Richard Feldman (Jan 18 2026 at 05:46):

true, but in --optimize builds the expects are removed, so the semantics of that function are supposed to match - just report, don't end the program

view this post on Zulip Rick Hull (Jan 18 2026 at 12:25):

ah, good point. in a test suite, keep going. but a failed runtime assertion should halt. so expect is not ideal in a "runtime test suite"

view this post on Zulip Rick Hull (Jan 18 2026 at 12:28):

Still wondering, if all host functions are impure by definition, and pure functions cannot call impure functions, so if my application is purely functional, then I cannot call any platform functions? This doesn't seem quite right.

view this post on Zulip Richard Feldman (Jan 18 2026 at 12:48):

so expect is not ideal in a "runtime test suite"

yeah, if you want the program to halt, that's what crash is for

view this post on Zulip Rick Hull (Jan 18 2026 at 13:06):

oh, good clarification. runtime expect throws an error (which would interrupt a typical test suite) but does not automatically halt

view this post on Zulip Richard Feldman (Jan 18 2026 at 13:37):

it doesn't interrupt the test suite, it adds to a list of failed expectations

view this post on Zulip Richard Feldman (Jan 18 2026 at 13:38):

and then at the end of the suite, they all get aggregated and reported together

view this post on Zulip Rick Hull (Jan 18 2026 at 14:09):

that's only the comptime expect at the toplevel, as executed by roc test, right? and what i'm calling runtime expect, within a block, would throw a runtime error if it fails, and this error would typically interrupt a naive test suite that is just a series of assertions. that is: a test suite which is not prepared to handle the error thrown by expect. or would such a test suite be forced to handle the error? i'm still trying to figure this stuff out but I'm sure it will become obvious to me with more usage

view this post on Zulip Richard Feldman (Jan 18 2026 at 14:14):

the number one rule of expect is that it never affects control flow in any way

view this post on Zulip Richard Feldman (Jan 18 2026 at 14:15):

no matter where it is used

view this post on Zulip Richard Feldman (Jan 18 2026 at 14:15):

it is a harmless report

view this post on Zulip Richard Feldman (Jan 18 2026 at 14:16):

maybe a better way to think of it is "debug print that an expectation was false, and then mark this test as 'must fail' when it finishes running"

view this post on Zulip Rick Hull (Jan 18 2026 at 14:38):

Thanks! Big fan of the podcast, and I made my introduction here about a year ago, but my focus shifted. Glad to be back

view this post on Zulip Anton (Jan 19 2026 at 11:29):

zig4lyfe

That would be cool for a tattoo :p
Fun fact: a former contributor has a tattoo of the Roc logo :roc:

view this post on Zulip Rick Hull (Jan 19 2026 at 19:39):

what are some guidelines for "platform modules" under roc-nightly? I know that they must contain at least one Type with the same name. I was going to make platform/Crypto.roc with nominal tag unions: SecretKey PublicKey Signature Digest but this isn't allowed

view this post on Zulip Rachael Sexton (Jan 20 2026 at 02:27):

I have a strange(?) question...

Most of the best functional workflows I've ever used were for Data science, and I'm seriously looking into how to get e.g. Arrow, BLAS, etc. bindings working in Roc.

My understanding right now is that those kinds of I/O would be done via a platform, right? So there might be an "arrow" platform, or a "BLAS" platform. But the problem I'm running into is ... I would never want to use _only_ BLAS, or _only_ Arrow, rather I would use them to accomplish something in the context of another platform (e.g. a basic-cli tool)

But I'm seeing the documentation tutorial says every app has "exactly one platform". What is considered "one platform"? In a declaration like:

app [main!] { cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.20.0/X73hGh05nNTkDHU06FHC0YfFaQB1pimX7gncRcao5mU.tar.br" }

is the platform only "cli" or is it the whole record? Can I have multiple keys in the platform declaration record?

view this post on Zulip Rick Hull (Jan 20 2026 at 02:46):

my take, as newbie but also a platform developer, is that you would incorporate all features into the platform. you can have a "BLAS" module or "arrow" module, and maybe a platform specific to each. but if you want both, you can have both, if you work to make them live together which is usually not difficult

view this post on Zulip Rick Hull (Jan 20 2026 at 02:49):

what is exactly considered one platform? basic-cli is an amazing resource. it has way more features than I would imagine for a basic-cli, but it also stays simple and approachable

view this post on Zulip Rick Hull (Jan 20 2026 at 02:50):

clone this https://github.com/roc-lang/basic-cli and poke around

view this post on Zulip Rick Hull (Jan 20 2026 at 02:51):

it looks like you are targeting the documented Roc, which I would call roc-alpha-4, aka the "old Rust compiler". Keep in mind, there is a "new Zig compiler" and the language is changing; I personally target roc-nightly, based on the new compiler (and it's a different language).

view this post on Zulip Rachael Sexton (Jan 20 2026 at 03:14):

Ah, but then how would someone else reuse my "blas platform" code? They would have to build their own platform that combines my BLAS I/O with their own platform?

view this post on Zulip Richard Feldman (Jan 20 2026 at 04:25):

so BLAS and LAPACK have been two longstanding questions in this area - but this is the first I'm hearing of Arrow! (I know almost nothing about data science; I only know about these libraries because of people asking about them in the context of Roc! :smile:)

view this post on Zulip Luke Boswell (Jan 20 2026 at 06:48):

@Rachael Sexton I think the running hypothesis is that platforms will evolve around a domain. So if you are working on a particular kind of software, and having these kind of libraries is necessary for e.g. performance reasons, then I would expect the platform author to think of a good API to integrate those. However I'm not sure they will be exposing the functionality 1-1 with those library APIs but maybe wrapping them in a more ergonomic or idiomatic way. So under the hood a platform may be using a particular library but this isn't a detail an application author would be concerned with.

view this post on Zulip Anton (Jan 20 2026 at 09:16):

A data science platform sounds like the way to go.

view this post on Zulip Richard Feldman (Jan 20 2026 at 12:49):

that's probably the way to go for now

view this post on Zulip Richard Feldman (Jan 20 2026 at 12:49):

personally I think the most promising long-term direction is using an LLM to port BLAS/LAPACK/etc. to pure Roc

view this post on Zulip Richard Feldman (Jan 20 2026 at 12:50):

they're all pure functions and our (currently non-SIMD) numeric code can optimize to the same things that LLVM optimizes to

view this post on Zulip Rick Hull (Jan 20 2026 at 13:20):

what are some guidelines for "platform modules" using the new compiler? I know that they must contain at least one type with the same name. I was going to make platform/Crypto.roc with nominal tag unions: SecretKey PublicKey Signature Digest but this isn't allowed

view this post on Zulip Rick Hull (Jan 20 2026 at 13:22):

If I just named it Signature.roc would that be expected to work? I am not sure about visibility / scoping. I ran in to not being able to resolve e.g. Digest from a test file

view this post on Zulip Anton (Jan 20 2026 at 13:59):

Let me take a moment to try some stuff

view this post on Zulip Rachael Sexton (Jan 20 2026 at 14:57):

Richard Feldman said:

personally I think the most promising long-term direction is using an LLM to port BLAS/LAPACK/etc. to pure Roc

Interesting. So, what about cases where a lightweight c library exists already, is it idiomatic for module/library authors to depend on c functions right now? E.g. nano arrow should make porting arrow to roc very easy, if so.

Similarly, I wouldn't want to reimplement e.g. pola.rs in roc myself, but it is a rust library that already gets used in node, r, python, and I believe available natively in Nushell

view this post on Zulip Anton (Jan 20 2026 at 15:04):

The platform can depend on C functions, Luke's raylib is basically a complex demonstration of how you can set something like that up.

view this post on Zulip Rick Hull (Jan 20 2026 at 15:35):

@Anton (platform module resolution) https://gist.github.com/rickhull/68f3fbf668db9f61598628b29ba0feb0

view this post on Zulip Anton (Jan 20 2026 at 15:37):

Thanks Rick, I will try to make that work or make an issue

view this post on Zulip Rick Hull (Jan 20 2026 at 15:59):

oh whoops, you'll need Signature.roc; updating UPDATED

My presumption is that I'm Doing It Wrong (tm)

view this post on Zulip Richard Feldman (Jan 20 2026 at 16:08):

Similarly, I wouldn't want to reimplement e.g. pola.rs in roc myself, but it is a rust library that already gets used in node, r, python, and I believe available natively in Nushell

I think pola.rs is a good model for what I'm talking about - the pola.rs folks didn't do FFI to the C code underlying the already-popular pandas, they built a new library in pure Rust :smile:

view this post on Zulip Richard Feldman (Jan 20 2026 at 16:09):

building new things can be done, and I think there's a lot of precedent for it being the way to get the best outcome!

view this post on Zulip Rick Hull (Jan 20 2026 at 16:40):

To further this idea, I am writing nostr-platform, mainly so I can build on top of libsecp256k1. I could implement Schnorr signatures in Roc -- I've already done it in Ruby, maybe the repo I am most proud of, done entirely without LLM assistance agents or code. (I used a lot of LLM assistance for understanding elliptic curve crypto. See the README.md -- it's great, and written by me!)

But in this case, it makes much more sense to rely on a battle-tested lib (Bitcoin!) for important crypto stuff.

view this post on Zulip Anton (Jan 20 2026 at 16:42):

for important crypto stuff.

Yeah in that case you want to use the original lib indeed

view this post on Zulip Rick Hull (Jan 20 2026 at 16:51):

@Anton for the platform module, I can access Signature.Digest but not Digest. so the module acts as a namespace. I would like to name it Crypto.roc and I'd be fine with Crypto.Signature but I have to expose a "Crypto type". is this a misfeature?

view this post on Zulip Anton (Jan 20 2026 at 16:52):

No, I think that is as intended

view this post on Zulip Rick Hull (Jan 20 2026 at 16:54):

So if I just want a Crypto namespace, what should a trivial Crypto type look like? or maybe I will have a real type? for what?

view this post on Zulip Rick Hull (Jan 20 2026 at 16:56):

alternatively, I could have Digest.roc PublicKey.roc etc. that seems fine, if maybe a bit chatty. Is that more along the intent of platform modules?

view this post on Zulip Anton (Jan 20 2026 at 16:56):

For the trivial type you can do Crypto := [].{}

view this post on Zulip Anton (Jan 20 2026 at 16:56):

@Richard Feldman may have useful thoughts here

view this post on Zulip Rick Hull (Jan 20 2026 at 17:06):

with more testing, I am thinking I should have these nominal tag unions be their own module. it just seems like less friction. but i am continuing to test.

view this post on Zulip Rick Hull (Jan 20 2026 at 17:11):

https://gist.github.com/rickhull/c5f63e552465180f4e3c76b99e460f57 (generated via: ./rocgist.sh test/signature.roc platform/Crypto.roc)

view this post on Zulip Rick Hull (Jan 20 2026 at 17:12):

this tells me that the trivial type as namespace is flawed. i am going to put the nominal tag unions as their own modules and move on

view this post on Zulip Luke Boswell (Jan 20 2026 at 19:17):

Anton said:

For the trivial type you can do Crypto := [].{}

We had a builtin named the same, though I guess now these crypto stuff would just live under Builtin now so that namespace is free to use if people want to roll thier own.

We decided that most of the core cryptographic algorithms should ge implemented by Roc so we can garuntee they are secure and avoid timing attacks. At least that is what I recall, I would need to dig out the zulip thread to refresh myself. We haven't implemented any crypto in the new builtins yet.

view this post on Zulip Luke Boswell (Jan 20 2026 at 19:19):

See https://github.com/roc-lang/roc/pull/6977

view this post on Zulip Luke Boswell (Jan 20 2026 at 19:22):

I dont see any issue with implementing algorthims in pure Roc for learning etc, but just wanted to mention this as we haven't talked about it in a while.

view this post on Zulip Rick Hull (Jan 20 2026 at 19:37):

Interesting. I have rolled my own crypto systems before, but always for test, not production, stuff like 3DES EDE-CBC; not a crypto engineer; I implemented schnorr sig as an exercise in learning elliptic curve crypto and to enable a pure ruby nostr impl. I don't think I was hitting a name clash with my Roc attempts. I have now abandoned the name "Crypto" in my current platform impl.

view this post on Zulip Rick Hull (Jan 22 2026 at 19:10):

I am working on ZIG_PLATFORM_GUIDE.md. This is a different document than what was here, earlier. This has a better starting basis, written mostly by me (!), and will be augmented.

I am using claude's help, and this is a little bit of the blind leading the blind, so please highlight any mistakes, errors, misconceptions, or needed fixes.

view this post on Zulip Rick Hull (Jan 22 2026 at 22:23):

@Luke Boswell ^^ if you get a chance

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:25):

It's very meh... there is some detail that is mostly right, and others that is overly specific to the zig template.

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:26):

I wouldn't want to share something like that as an authoritative guide or anything as it would probably mostly confuse people

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:27):

Regarding platform documentation -- I think we are intentionally leaving this undocumented for now.

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:27):

There are higher priorities, and platform development requires a much higher level of knowledge and experience than application development.

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:28):

There are many details that are still being validated with the new calling convention. I think it should be stable but there are still a lot of things that just haven't been built yet and so some things may need to change

view this post on Zulip Rick Hull (Jan 22 2026 at 22:28):

Good to know. I am basically documenting what I learned about the Zig template. it sounds like basic-cli can be used now? I didn't totally realize that -- it just needs building from source?

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:29):

E.g. we probably need to sort out the Windows linking story -- but that is hard when we don't have any super experienced Windows devs contributing right now, so it just takes a long time to do anything related with that. I take bites at it every now and then because I'd love to see it happen (for the Windows developers out there) but it can be a slog

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:29):

Rick Hull said:

Good to know. I am basically documenting what I learned about the Zig template. it sounds like basic-cli can be used now? I didn't totally realize that -- it just needs building from source?

Yeah it's working nicely

view this post on Zulip Rick Hull (Jan 22 2026 at 22:30):

i want to get basic-cli going now -- what's step 1, just poke around the repo HEAD?

view this post on Zulip Rick Hull (Jan 22 2026 at 22:32):

I have a windows box, and if there is a way to script builds on windows, i can poke around a bit. but i'm guessing it would be a huge PITA to get a semblance of a build environment going on a typical windows desktop

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:32):

Clone https://github.com/roc-lang/basic-cli then git checkout migrate-zig-compiler then ./build.sh

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:32):

You will then be able to run the examples using the platform locally

view this post on Zulip Luke Boswell (Jan 22 2026 at 22:34):

Rick Hull said:

I have a windows box, and if there is a way to script builds on windows, i can poke around a bit. but i'm guessing it would be a huge PITA to get a semblance of a build environment going on a typical windows desktop

It's not a huge PITA or anything... it's just that it requires a fairly deep level of expertise in linking and low level things. Not an area the LLMs are able to provide much assistance... it feels more like voodoo science than engineering

view this post on Zulip Rick Hull (Jan 22 2026 at 22:35):

that's like taking the One Ring from gollum :rolling_on_the_floor_laughing:

view this post on Zulip Rick Hull (Jan 22 2026 at 22:39):

I've reframed that doc as ZIG_PLATFORM_GUIDE.md and it lives in roc-init for now. I think it's ok to have "rough guides" that are not official docs to be relied upon

view this post on Zulip nandi (Jan 22 2026 at 22:57):

Luke Boswell said:

Clone https://github.com/roc-lang/basic-cli then git checkout migrate-zig-compiler then ./build.sh

I've been working on my own branch, didn't realize this already existed lol

view this post on Zulip Luke Boswell (Jan 22 2026 at 23:07):

I would say the basic-cli migration is like 3/4 done -- all the hard stuff is behind us, we have resolved all the known bugs that were holding it back now, and we have CI working for all the supported targets. It's only got these modules implemented Cmd, Dir, Env, File, Path, Random, Sleep, Stdin, Stdout, Stderr, Utc so missing things like Http etc... and the implementation of the se modules is definitely a WIP as we need to do a few passes to make these more idiomatic with the new static dispatch approach.

view this post on Zulip Romain Lepert (Feb 03 2026 at 23:07):

Richard Feldman said:

they're all pure functions and our (currently non-SIMD) numeric code can optimize to the same things that LLVM optimizes to

Here is the kind of code that needs to be written in Mojo to write efficient matmul
https://github.com/jon-chuang/mojo/blob/422256e2490a1899b204e7b3a9cae2c6007433e8/examples/matmul.mojo

It is all about tiling SIMD vectors and doing ops on them. The best tiling strategy depends on the matrix dimensions (which is usually only known at runtime) and the host architecture. Numpy dispatches to the best kernel at runtime. Mojo compiles the exact best kernel only through comptime parametrization. Python using Mojo would JIT compile specialized kernels for the current matrices.

Even then you don't exactly meet numpy(OpenBLAS) performance. https://github.com/modular/modular/pull/3248 (NB: unreliable benchmarking).

These are the kind of challenges that roc would have to enable to reimplement BLAS/LAPACK libraries

view this post on Zulip Richard Feldman (Feb 04 2026 at 02:48):

whoa, this is super helpful @Romain Lepert , thank you so much! :star_struck:

Romain Lepert said:

The best tiling strategy depends on the matrix dimensions (which is usually only known at runtime) and the host architecture. Numpy dispatches to the best kernel at runtime. Mojo compiles the exact best kernel only through comptime parametrization. Python using Mojo would JIT compile specialized kernels for the current matrices.

just to check my understanding: the "kernel" in this case refers to the tiling strategy?

I think from a comptime perspective we'd be on par with mojo, since if the matrices are statically known, we'd do the dispatch at comptime too (since these are all pure functions).

that said, I don't know if any of the tricks they used to get 3x the perf of numpy (with the extreme caveat that the numpy benchmarks they're comparing to have been really inconsistent, and an earlier run would have had the reverse outcome - numpy being 3x the perf of mojo instead of the other way around) require using memory-unsafe APIs, which would be the main concern I'd have about achieving perf parity there

view this post on Zulip Richard Feldman (Feb 04 2026 at 02:48):

cc @Brendan Hansknecht

view this post on Zulip Richard Feldman (Feb 04 2026 at 02:48):

we don't have any SIMD APIs currently, and a major reason for that is my not knowing what to target :laughing:

view this post on Zulip Richard Feldman (Feb 04 2026 at 02:49):

but if we had a realistic target of "be able to compete with numpy using only memory-safe pure Roc APIs" that would be excellent for unblocking that design work! :smiley:

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 03:23):

Haha, that GitHub diff is so useless. Looks to be showing lots of random changes from main rather than just the example changes

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 03:36):

Yeah, so what is missing for roc to do that:

  1. Simd instructions. Preferably with explicit load and store, but not strictly required. Without explicit load store, you depend on roc (and minorly llvm), to properly remove all refcounting and bounds checking.
  2. Explicit loop unrolling.
  3. Vectorize is just a convenience and I don't think is needed.
  4. Multithreaded work queuing/distribution
  5. Comptime integer parameters and the ability to do math on them. Not technically required but really required if you want a usable API. Otherwise you need every matrix size to be a different type and to explicitly be managed. It just isn't practical with large matrices.
  6. System information exposed to roc at compile time so it can specialize to hardware
  7. GPU/XPU support if you want the full magic of mojo.

view this post on Zulip Richard Feldman (Feb 04 2026 at 06:42):

isn't loop unrolling also a convenience?

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 07:28):

Sadly not. It can be fundamental for performance

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 07:29):

Of course when everything goes right llvm can do it.

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 07:30):

But sometimes you need to fully unroll or even partially unroll to get better utilization. Balancing code bloat/instruction cache size vs number of branch checks (even if fully predicted it can cause issues)

view this post on Zulip Richard Feldman (Feb 04 2026 at 17:18):

regarding comptime type parameters with arithmetic - I'm surprised that would be considered a requirement for ergonomics. Lots of languages support these use cases from a perf perspective, but which ones actually have that feature? :sweat_smile:

is it that dynamic languages like Python don't need to care about the static type implications of the APIs, so those ergonomics are out of scope?

view this post on Zulip Romain Lepert (Feb 04 2026 at 20:30):

In Mojo you write

fn matmul[M: Int, N: Int, K: Int](a: Tensor, b: Tensor, c: Tensor)

and inside you might need to do some arithmetic on the M, N, K comptime type parameters

in C++ you don't have comptime type parameters so you have to use template for that which has a lot worse development ergonomics

template<int M, int N, int K>
void matmul(Tensor&, Tensor&, Tensor&);

in python you don't care because you delegate to a precompiled library that would look like this in C++

void matmul(Tensor& a, Tensor& b, Tensor& c)
{
    const int M = a.shape[0];
    const int N = b.shape[1];
    const int K = a.shape[1];

    // Example: a small hand-picked set of fast kernels
    if (M == 128 && N == 64 && K == 256) {
        matmul<128, 64, 256>(a, b, c);
        return;
    }

    if (M == 256 && N == 64 && K == 256) {
        matmul<256, 64, 256>(a, b, c);
        return;
    }

    if (M == 128 && N == 128 && K == 256) {
        matmul<128, 128, 256>(a, b, c);
        return;
    }

    // fallback
    matmul_generic(a, b, c);
}

view this post on Zulip Brendan Hansknecht (Feb 04 2026 at 23:34):

Yeah, Romain has the right basis. Fundamentally, when python calls the high performance libaries, the first step is to dispatch based on the shape to an optimized kernel for the shape. When you do this, you end up having N different kernels for various kinds of shapes. This is the standard way to deal with dynamism. It actually limits reaching peak performance in some case.

If you are to go to the very extreme like is seen with max graphs:

  1. Every kernel shape can be specialized and custom compiled for. That said, for exceptionally dynamic dimensions you still do the mapping form essentially infinite options to N kernel choices.
  2. Back to back or neighboring operations can often be fused to really push performance. So instead of having a matmul kernel and a relu kernel. You have one super kernel that does matmul + relu. This kernel has all the matmul specialization from 1. It also halves the number of loads and stores by merging the relu operation into the matmul operations.

I don't expect roc to compete in this space. I don't think it needs to in general. That sad, I do think it should be able to compete with numpy or blas or lapack with the right user guiding it. Those libraries tend to have hand rolled loops but minimal extreme specialization. They tend to still treat shapes fully dynamically.


Last updated: Feb 20 2026 at 12:27 UTC