Stream: beginners

Topic: what does ! behind an function mean


view this post on Zulip Jonas (Dec 05 2024 at 22:01):

what does ! behind an function mean

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:02):

It means that a function is effectful, or that is does stuff outside of the function.

view this post on Zulip Anthony Bullard (Dec 05 2024 at 22:02):

The function returns a task, or soon, that it is an impure function - which semantically means something similar

view this post on Zulip Jonas (Dec 05 2024 at 22:03):

thanks, is a task smth i have to unwrap like an Result

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:03):

For example, readFileBytes! : Str => List U8 won't always return the same thing because it reads a file from the "outside world" aka your filesystem

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:04):

So... awkwardly, Roc is in between two effectful ! worlds right now

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:04):

The old one is Tasks, which are basically a Task ok err := {} -> Result ok err "thunk"

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:05):

Those need to be wrapped like Result, yes

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:06):

The new world is just purity inference, which is where normal, "pure" functions are basically the exact same as effectful functions, except we enforce that functions that "do stuff outside" have an ! at the end of their name

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:06):

For the next month or two, the first one is what you'll be using, meaning you need to return Task.ok yourValue instead of just Ok yourValue

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:07):

But in the future, it'll be just Ok yourValue

view this post on Zulip Nicola Peduzzi (Dec 05 2024 at 22:07):

I think it's well explained in the tutorial: https://www.roc-lang.org/tutorial#the-postfix-await-operator

basically

main =
    Stdout.line! "hello"
    Stdout.line! "word" # note, this ! can be omitted and the desugaring is the same (because it's the last one before returning)

becomes

main =
    Task.await (Stdout.line "hello") \_ ->
        Stdout.line "world"

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:08):

Yep! That's exactly what's happening right now.

view this post on Zulip Jonas (Dec 05 2024 at 22:08):

does it mean the api will change to Result instead of Task?

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:09):

It can be a Result, it can also not be a Result

view this post on Zulip Jonas (Dec 05 2024 at 22:09):

oh

view this post on Zulip Jonas (Dec 05 2024 at 22:09):

ok

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:09):

Something like readFileBytes! : Str => Result (List U8) ReadErr will use a Result because it might fail

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:09):

But something like envVars! : {} => Dict Str Str won't because it can't fail

view this post on Zulip Jonas (Dec 05 2024 at 22:09):

i have primarily experience with Rust and Ocaml

view this post on Zulip Nicola Peduzzi (Dec 05 2024 at 22:16):

Sam Mohr said:

Something like readFileBytes! : Str => Result (List U8) ReadErr will use a Result because it might fail

does it mean (or will it mean?) that without the !:

readFileBytes : Str -> Task (Result (List U8) ReadErr) [SomeOtherErr] ?

and what is the fat arrow =>?

I'm missing a bunch of updates :D

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:21):

We're in between a few different "shapes" of Roc, so we haven't been communicating everything very clearly

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:21):

The current effectful Roc with Task has two types parameters, ok and err, since it always returns a Result under the hood

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:22):

So it'd be readFileBytes : Str -> Task (List U8) ReadErr

view this post on Zulip Sam Mohr (Dec 05 2024 at 22:23):

The => implies that a function is effectful. The name ending in ! also implies it. It's arguably redundant, but there are some cases with nested type signatures where you need => for clarity

view this post on Zulip Nicola Peduzzi (Dec 05 2024 at 22:27):

I see so in this potential future the ! would be "in the function name" so to speak? and it would have the same meaning of a => that is: this function may return a different value even if input do not change?

view this post on Zulip Anthony Bullard (Dec 05 2024 at 22:28):

Basically the ! is to tell you - without seeing the types - that an effect is happening

The => tells you an effect is happening without seeing the implementation

view this post on Zulip jan kili (Dec 10 2024 at 16:38):

@Sam Mohr I updated the tutorial recently to explain both the current implementation of ! as operator and the upcoming-but-not-ready-yet switch to a suffix. I hope that the new Under Construction section of the tutorial provides a sufficient first exposure of these concepts!

view this post on Zulip jan kili (Dec 10 2024 at 16:39):

I think this month we shouldn't mention purity inference concepts/changes to anyone who isn't specifically asking about them. Roc has enough mental overhead for newcomers with the features that have already landed!


Last updated: Jul 06 2025 at 12:14 UTC