Stream: beginners

Topic: ✔ print err if file not found


view this post on Zulip Travis (Oct 12 2022 at 14:07):

is there some way to accomplish this?

contents <- path
  |> Path.fromStr
  |> File.readUtf8
  |> Task.onFail \_ -> Stderr.line "oops" |> Task.await

i get the errors

── TOO MANY ARGS ────────────────────────────────────── platform-test/main.roc ─

The onFail function expects 2 arguments, but it got 3 instead:

20│          contents <- path |> Path.fromStr |> File.readUtf8 |> Task.onFail \_ -> Stderr.line "oops" |> Task.await
                                                                  ^^^^^^^^^^^

Are there any missing commas? Or missing parentheses?


── TOO FEW ARGS ─────────────────────────────────────── platform-test/main.roc ─

The await function expects 2 arguments, but it got only 1:

20│          contents <- path |> Path.fromStr |> File.readUtf8 |> Task.onFail \_ -> Stderr.line "oops" |> Task.await
                                                                                                          ^^^^^^^^^^

view this post on Zulip Travis (Oct 12 2022 at 14:11):

i'm thinking Task.attempt might work

view this post on Zulip jan kili (Oct 12 2022 at 14:12):

Syntax aside, I don't think stderr writing should pipe to a variable named contents... mixing steps?

view this post on Zulip jan kili (Oct 12 2022 at 14:13):

Today you'll need to add parentheses around your mid-pipeline function

view this post on Zulip jan kili (Oct 12 2022 at 14:14):

What type are you aiming for for contents?

view this post on Zulip Travis (Oct 12 2022 at 14:15):

contents is a List u8 i believe

view this post on Zulip Travis (Oct 12 2022 at 14:16):

wait maybe its a Str. next line is:
raw = Str.toUtf8 contents

view this post on Zulip jan kili (Oct 12 2022 at 14:16):

(there is a File.readBytes that you might like)

view this post on Zulip jan kili (Oct 12 2022 at 14:17):

But yes, that sounds like a good aim, for contents to be a str

view this post on Zulip Travis (Oct 12 2022 at 14:17):

yeah i don't really care what type contents is, Str or List u8 is fine. but lets just say Str for now

view this post on Zulip jan kili (Oct 12 2022 at 14:18):

Unfortunately, after File.readUtf8 returns a task that could Ok or Err, you're not handling/extracting either the Ok or Err cases

view this post on Zulip Travis (Oct 12 2022 at 14:18):

this is just for demoing my zig platform

view this post on Zulip jan kili (Oct 12 2022 at 14:19):

I recommend changing contents to result

view this post on Zulip jan kili (Oct 12 2022 at 14:20):

deleting the onFail logic and just awaiting the file read

view this post on Zulip jan kili (Oct 12 2022 at 14:20):

then on a new line handle the result

view this post on Zulip Travis (Oct 12 2022 at 14:20):

ok sounds good. i'll see what i can do.

view this post on Zulip Travis (Oct 12 2022 at 14:20):

thanks!

view this post on Zulip jan kili (Oct 12 2022 at 14:20):

After that works, recombining the lines is still an option but you'll have a working baseline :)

view this post on Zulip jan kili (Oct 12 2022 at 14:20):

You bet!

view this post on Zulip jan kili (Oct 12 2022 at 14:22):

And in case it's a point of confusion, stderr writing isn't a side effect

view this post on Zulip Travis (Oct 12 2022 at 14:22):

hold on. how can i get a Result without stopping the subsequent chain of Tasks? Task.attempt?

view this post on Zulip Travis (Oct 12 2022 at 14:23):

thats what i was trying to use but having some problems. does it sound like it should work?

view this post on Zulip Travis (Oct 12 2022 at 14:24):

maybe you are saying instead of backpassing handle contents in a new function?

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:25):

Shouldn't this work?

contents <- path
  |> Path.fromStr
  |> File.readUtf8
  |> Task.onFail (\_ -> Stderr.line "oops")
  |> Task.await

view this post on Zulip Travis (Oct 12 2022 at 14:26):

ooh seems closer. now i get an unexpected type error...

view this post on Zulip Travis (Oct 12 2022 at 14:27):

the diff is Task {} vs Task Str

view this post on Zulip Travis (Oct 12 2022 at 14:27):

This 2nd argument to onFail has an unexpected type:

31│            |> Task.onFail (\_ -> Stderr.line "oops")
                               ^^^^^^^^^^^^^^^^^^^^^^^^

The argument is an anonymous function of type:

    [FileReadErr Path ReadErr,
    FileReadUtf8Err Path [BadUtf8 Utf8ByteProblem Nat]*]* ->
    Task {} * [Read [File]*, Write [Stderr]*]a ?

But onFail needs its 2nd argument to be:

    [FileReadErr Path ReadErr,
    FileReadUtf8Err Path [BadUtf8 Utf8ByteProblem Nat]*]* ->
    Task Str * [Read [File]*, Write [Stderr]*]a ?

view this post on Zulip Travis (Oct 12 2022 at 14:28):

last line and 4th from last

view this post on Zulip Travis (Oct 12 2022 at 14:28):

seems i just need to return a string there

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:29):

Ah, onFail expects you to return a task that gives you a new value for contents. So a Str

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:29):

So this would work, but doesn't print of coures

contents <- path
  |> Path.fromStr
  |> File.readUtf8
  |> Task.onFail (\_ -> Task.succeed "Some backup content value")
  |> Task.await

view this post on Zulip Travis (Oct 12 2022 at 14:30):

ah neat. well atleast i'll be able to see that an error happened. this will work ok for my use case.

view this post on Zulip Travis (Oct 12 2022 at 14:31):

thank you both :+1:

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:31):

So the current implementation of onFail doesn't work the way we expected here.

I think you would need to do:

contents <- path
  |> Path.fromStr
  |> File.readUtf8
  |> Task.onFail (\e ->
    _ <- Stderr.line "oops" |> Task.await
    Task.fail e
  )
  |> Task.await

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:31):

Probably would want a different helper function

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:32):

So I guess onFail is really "if I fail, try to recover and continue by doing this"

You want, "if I fail, do this, but stay as a failure"

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:34):

This is probably worth making an issue for, or at least a discussion in #ideas. Seems like a generally useful Task function that we are missing. Also a possible naming confusion/conflict.

view this post on Zulip Travis (Oct 12 2022 at 14:35):

yes. it would be nice to have a helper for that. i agree.

view this post on Zulip Travis (Oct 12 2022 at 14:36):

maybe ill post some of this in ideas in a bit.

view this post on Zulip Notification Bot (Oct 12 2022 at 14:38):

Travis has marked this topic as resolved.

view this post on Zulip jan kili (Oct 12 2022 at 14:56):

That last code snippet works if the file exists (the Ok case), but it panics if it doesn't (the Err case):

thread 'main' panicked at 'not yet implemented: Report a file open error', src/lib.rs:375:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fatal runtime error: failed to initiate panic, error 5
Aborted (core dumped)

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:59):

Oh, that's not a roc issue, that's a rust platform issue.

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:59):

The platform doesn't handle all errors yet

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 14:59):

So some cases it just panics

view this post on Zulip jan kili (Oct 12 2022 at 15:01):

Oh... Oh! I just now understood the "stderr quick exit" approach you two are both taking... that's cool.

view this post on Zulip Travis (Oct 12 2022 at 15:01):

oh reeeeaaalllly? :big_smile: i think i was able to get it working in my zig platform

view this post on Zulip Travis (Oct 12 2022 at 15:01):

$roc platform-test/main.roc -- asfd
🔨 Rebuilding platform...
----
File.readUtf8 platform-test/main.roc:
----
app "platform-main"
    packages { ...(truncated)
----
not-a-file:               Not Found

view this post on Zulip Travis (Oct 12 2022 at 15:02):

like just got it working this morning doing some error handling in roc_fx_fileReadBytes

view this post on Zulip jan kili (Oct 12 2022 at 15:03):

I never realized you could write a backpassing chain that handles early exits halfway through...

view this post on Zulip jan kili (Oct 12 2022 at 15:03):

That's great!

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:03):

I mean the pipelining is handling the early exits. The backpass once triggered would be too late.

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:04):

That said, it is also valid to just accumulate the errors and handle them all at the end in one place.

view this post on Zulip jan kili (Oct 12 2022 at 15:06):

        happy <-
            input
            |> process
            |> ifSad exitSadly
            |> await
        smile <-
            happy
            |> react
            |> ifFrown goToFrownTown
            |> await
        smile
        |> welcomeToSmileTown

view this post on Zulip Ghislain (Oct 12 2022 at 15:06):

Brendan Hansknecht said:

That said, it is also valid to just accumulate the errors and handle them all at the end in one place.

Related to this, if you accumulate all errors, how can you avoid error Tag naming conflict from different lib/package?

view this post on Zulip jan kili (Oct 12 2022 at 15:08):

@Brendan Hansknecht I credit backpassing with this "early escape" functionality, because if you only have |>s with no <- then at the end of the pipeline you'll have to handle a complex multi-type for all possible outcomes.

view this post on Zulip jan kili (Oct 12 2022 at 15:08):

...hence why I was going to suggest changing contents to result and then doing the Err handling after.

view this post on Zulip jan kili (Oct 12 2022 at 15:10):

With <-, you can add mid-pipeline handler steps to narrow the type "returned" by <-, because you're essentially narrowing the branches that the final callback must handle.

view this post on Zulip jan kili (Oct 12 2022 at 15:11):

This might be understood by everyone else here, but it's news to me :D

view this post on Zulip Travis (Oct 12 2022 at 15:11):

related to this, is there a way to get the tag name as a string? or would i just have to do a manual switch?

|> Task.onFail (\_ -> Task.succeed "Not Found") #TODO print error tag somehow

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:11):

your would just add a lambda to the last await in the pipeline, it would be the same thing with more indentation.

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:11):

manual switch

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:12):

Tag naming conflict from different lib/package?

Wrap them by package or function or etc

view this post on Zulip Travis (Oct 12 2022 at 15:12):

i think i'm spoiled by zig here

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:12):

haha. Sounds reasonable. Zig is a nice language.

view this post on Zulip Travis (Oct 12 2022 at 15:13):

yeah @tagName would be nice here

view this post on Zulip Brendan Hansknecht (Oct 12 2022 at 15:20):

That's something else that could be worth putting in the #ideas stream.


Last updated: Jul 06 2025 at 12:14 UTC