Stream: advent of code

Topic: 2022 feedback!


view this post on Zulip Richard Feldman (Dec 18 2022 at 10:35):

hello everyone! If you did any amount of Advent of Code in Roc this year, I'd love to hear your feedback about the experience!

in the past for things like this we've done a video chat - if that sounds good to you, here's a link for coordinating on when we can all make it: https://www.when2meet.com/?18034195-ZJlyp - alternatively, if you'd rather share feedback in written form, feel free to either post it here or DM it to me...whatever you prefer, I'd love to hear about how the experience went - whatever comes to mind!

view this post on Zulip Luke Boswell (Dec 19 2022 at 08:02):

Advent of Code 2022 Feedback and Observations

I had a lot of fun working through the AoC puzzles; and some friendly competition with my mates who insist on using legacy technologies. :wink:

My first introduction to this kind of challenge was for Roctoberfest. My experience has been similar, though I managed to get much further this time around. I have enjoyed writing Roc apps, learning more about the language and finding new ways to solve problems. The best part has been comparing my solutions with other people, which really highlighted different approaches to the same problem.

I experienced some issues using Roc which was what I expected; however I tried to focus on contributing bug reports or ideas where I could. My progress through the challenges has slowed recently. I think the main reasons for this is; the puzzles are getting harder, I’m getting distracted with other things, coming across bugs which are hard to workaround, and Roc doesn’t have a mature ecosystem of libraries for common algorithms, data structures, visualisations etc.

Parsers are fun, not-that-hard, and very worthwhile to learn. I’ve never really had much need to write a parser, the occasional regex has always been more than sufficient. I thought parsers were difficult and time consuming to write and test. However, during this AoC I started writing parsers in an attempt to learn more. I’m still a beginner; and can see there is much more to learn, but from my experience I would highly recommend using parsers to anyone, especially beginners.

URL packages are great to work with. I’ve had no issues and found they really helped to reduce the friction to write an app. I could just copy-paste code into a file, type roc run and it ‘just worked’! As someone who doesn’t live in a cli, I found this a significant improvement over googling how to write a symlink each time, or writing my apps in a roc subdirectory.

I had some trouble learning how to do Task management and error handling. Roc felt strict sometimes; wouldn’t run my app, I couldn’t isolate the issue and the errors were confusing. I didn't find many examples of how to do Tasks or handle errors properly. However; I think my experience has now been overtaken by events, and I don’t think it is likely to be repeated in future. There have been changes to the API and at least one bug here that I experienced. I think a relevant lesson here is that it will be important for an introduction to Roc programming and using Tasks to include working examples and show error handling. Note that at the start of AoC there weren’t many (any?) examples of Tasks in the wild; this is no longer the case. The pattern of sequencing Tasks with backpassing syntax is really nice, just new and different enough from patterns in other languages.

Minimising errors and reporting crashes was easy to do and really helped the team find and fix compiler issues. I experienced plenty of crashes and panics; usually due to my lack of understanding or a crazy misapplication of syntax. I was encouraged by the team who have consistently asked me to raise issues when I find them. I found the process to minimise these examples to be straightforward and also helped me to understand my code better in the process. All I needed to do was copy-paste the app into a new file and then just repeatedly delete things and run the code until I got to a minimal example. Simple enough, but something I haven’t needed to do before.

Thank you to the Roc contributors for your work building a great language. It’s awesome to see all the progress; and I feel lucky to be part of the development at this time.

view this post on Zulip Richard Feldman (Dec 19 2022 at 11:32):

thank you for the feedback and the kind words, Luke! :smiley:

view this post on Zulip Richard Feldman (Dec 19 2022 at 11:33):

besides fixing the Task-related bug, this tells me I should make sure to prioritize explaining Task error handling in the tutorial :thumbs_up:

view this post on Zulip Erik (Dec 19 2022 at 22:54):

On error handling it is so cool that error tags combine and "just work".

Elm (does not compile)

type ThingErr
    = Wat
    | Hmm


thing : Result ThingErr {}
thing =
    Err Wat


type Thing2Err
    = Other
    | Stuff


thing2 : Result Thing2Err {}
thing2 =
    Ok {}


dooStuff =
    thing |> Result.andThen (\_ -> thing2)

Roc (Does compile!)

ThingErr : [Hmm, Wat]

thing : Result {} ThingErr
thing = Err Wat

Thing2Err : [Other, Stuff]

thing2 : Result {} Thing2Err
thing2 = Ok {}

dooStuff : Result {} [Hmm, Other, Stuff, Wat]
dooStuff =
    thing
    |> Result.try \_ -> thing2

view this post on Zulip Richard Feldman (Dec 19 2022 at 23:21):

yeah, this was the original motivation for having tag unions in the language! :smiley:

view this post on Zulip Shritesh Bhattarai (Dec 20 2022 at 17:40):

Here's a few notes about my experience:

view this post on Zulip Anton (Dec 20 2022 at 18:21):

Thanks for the feedback @Shritesh Bhattarai!

view this post on Zulip Kevin Gillette (Dec 22 2022 at 23:03):

There were a number of string manipulation functions that I missed not having, such as:

  1. Being able to trim a prefix/suffix or a set of graphemes from the start or end string: right now, only spacing can be trimmed. Technically replaceFirst and replaceLast can be used for this in conjunction with startsWith and endsWith, though it's not as convenient.
  2. A splitLines function that does the right thing with an input that ends with a newline character(s) ("line terminator" interpretation) or does not ("line separator" interpretation).
  3. Checked vs non-checked versions of any string manipulation function that returns a Result. I may want to replace matching substrings but don't necessarily care whether the substring was present.

Additionally, I found a couple places when doing string manipulation where it would've been nice to be able to re-declare an identifier within the same scope (the same way that Rust permits), i.e. by shadowing the previous declaration. An example would be splitting a string into words, then incrementally consuming each of those words: with redeclaration, I could have a words identifier that I peel words off the front of, and have a successively smaller list of remaining words; without such an ability, I need to use different variable names (naming is hard), or I need to carefully count indices.

view this post on Zulip Georges Boris (Dec 22 2022 at 23:46):

+1 to shadowing - even though I love a language like Elm, I've been using Elixir a lot and shadowing never caused me any bugs there. However, not shadowing did cause bugs for me on Elm since I need to maintain multiple versions of the same thing on the same scope with the same type, but if I reference an old one by mistake the compiler is not helpful (since they're the same type). maybe a restricted shadowing where only things with the same type could be generated would be ideal?

view this post on Zulip Brendan Hansknecht (Dec 23 2022 at 00:59):

I tend to try and rewriting things that require shadowing with pipelining, but shadowing would be more flexible.

view this post on Zulip Brendan Hansknecht (Dec 23 2022 at 00:59):

Definitely think it would be a nice addition based on my current experience.

view this post on Zulip Brendan Hansknecht (Dec 23 2022 at 01:00):

Though i think maybe shadowing should be limited to scopes somehow. So can't shadow top level declarations or functions which might get called recursively....not sure the best rule here. Maybe the type idea above would work

view this post on Zulip Richard Feldman (Dec 23 2022 at 03:37):

@Kevin Gillette want to open a new topic in #ideas about shadowing so we can discuss more there?

view this post on Zulip Brendan Hansknecht (Dec 23 2022 at 03:38):

Hmm....this said, a common use case in rust for shadowing is explicitly changing types. So path as a string and then path as a PathBuf. And other things of that nature.

view this post on Zulip Marten (Dec 23 2022 at 18:44):

I like the language and I had fun :)

I should've kept a list of stuff that came up as I went along, but here's what I can recall:

view this post on Zulip Kevin Gillette (Dec 26 2022 at 02:14):

I've had a good number of times in which i used successive backpassing with Result.map and saw type mismatches from nested results, and it took me a while to get comfortable enough with the Roc mindset to realize i needed Result.try in such cases.

This is an area where documentation could be more helpful to beginners if it includes some wording along the lines of "you want this function if..."


Last updated: Jul 06 2025 at 12:14 UTC