Stream: beginners

Topic: Allow underscores in field names and variable names #3026


view this post on Zulip Paul Wickham (Dec 29 2023 at 08:02):

Hi Everyone,

Can anybody please tell me is it possible to underscore in var names / fields?

I found this issue: https://github.com/roc-lang/roc/issues/3026

And it clearly states that it is possible to use underscore. But when I type in editor or repl something like a_a = 1 instead of a = 1 - it doesn't work. Same for { a_a : 1 }

Thank you.

view this post on Zulip Anton (Dec 29 2023 at 08:37):

@Richard Feldman

view this post on Zulip Richard Feldman (Dec 29 2023 at 13:26):

if I remember correctly, I think we decided on Zulip to hold off on changing the design there, and to leave underscores out for now

view this post on Zulip Paul Wickham (Dec 29 2023 at 14:28):

Ouh, I'd prefer to have the option. I'll look at the #3026 - maybe I figure out how to hack "my" Roc.

Thank you.

view this post on Zulip Paul Wickham (Dec 29 2023 at 14:30):

Ok, I take that back - the issue is not associated with a commit. So I won't figure out how to patch it. No problem, no underscores for me ;-)
Thank you.

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

I would like to be able to use underscores in special situations.

For example, I like to name test functions with underscores, even when the naming convention of the language suggests CamelCase. I was convinced by Kevlin Henney in this talk: https://m.youtube.com/watch?v=MWsk1h8pv2Q&si=QPoqmM85AifspmZU&t=19m

I know, you cannot name tests in roc, but I still hope, that this will change in the future :stuck_out_tongue_wink:

Another case, where I used underscores in function names in Go (has a CamelCase convention) was in a situation of auto generated code, where it was impossible/very hard to get unique names without underscores. The data contained names like foo/bar_blub and foo_bar/blub. So I needed a different way to translate the slash and the underscores. In the end, I used FooBar_Blub and Foo_BarBlub. I don't like it, but I don't know, what I would have done, if Go would not allow underscores in their names.

view this post on Zulip mark.r (Dec 29 2023 at 16:19):

Hello,

If there is an easy way how to hack the Rust implemetation as @Paul Wickham wanted to do, I'm happy to test it during my limited use.

@Richard Feldman If it is easy as changing abcdefghijklmnopqrstuvwxyz to abcdefghijklmnopqrstuvwxyz_ please let us know where to add _ in the codebase. I searched on github for something like Vec<char> = s.chars().collect(); but I guess it is more complicated since I didn't find anything interesting...

view this post on Zulip rudolf (Dec 29 2023 at 17:02):

I don't need the prime symbol. But I do miss underscore.

view this post on Zulip Richard Feldman (Dec 29 2023 at 17:12):

rudolf said:

I don't need the prime symbol. But I do miss underscore.

would this still be the case if #ideas > Shadowing Sigil was implemented?

view this post on Zulip rudolf (Dec 29 2023 at 17:53):

I haven't written enough code to need shadowing. My take is that the limitation of [0-9A-Za-z] characters is too restrictive. I'd like to have at least one special and underscore makes more sense than any other.

It might not be the best practice in Elm/Roc to use underscore but it is handy to have the option. For example, in Haskell, a functionName_ usually means it is monadic. I saw people using a_b for conversion functions. And it is nice to have an underscore for record field names so your brain doesn't need to map between fullName in Roc and full_name in JSON you're reading.

view this post on Zulip geor (Dec 30 2023 at 09:17):

mark.r said:

please let us know where to add _ in the codebase.

Same. Please let us know so we can modify Roc for our own use.

I registered on Zulip just to figure out what special characters can be used, assuming that something like ' or - can be used because _ doesn't work. We need at least one special character, and I'd prefer _ over Unicode Emoji char. :smile: .

view this post on Zulip Anton (Dec 30 2023 at 09:42):

You can change this line to if ch.is_alphabetic() || ch.is_ascii_digit() || ch == '_' {. That allows _ in identifiers but not as the first character. This change worked with one basic test, it may not play nice with roc format or the language server though, so no guarantees.

view this post on Zulip Richard Feldman (Dec 30 2023 at 12:40):

geor said:

We need at least one special character

I'm curious - what specific use cases do you want it for?

view this post on Zulip Richard Feldman (Dec 30 2023 at 12:54):

rudolf said:

My take is that the limitation of [0-9A-Za-z] characters is too restrictive. I'd like to have at least one special and underscore makes more sense than any other.

It might not be the best practice in Elm/Roc to use underscore but it is handy to have the option. For example, in Haskell, a functionName_ usually means it is monadic. I saw people using a_b for conversion functions. And it is nice to have an underscore for record field names so your brain doesn't need to map between fullName in Roc and full_name in JSON you're reading.

It's not just an Elm/Roc thing - underscores are also allowed in JavaScript, Java, C#, and Go, and I don't see them used in any of these ways in those languages. They certainly all use JSON and conversion functions!

view this post on Zulip Richard Feldman (Dec 30 2023 at 13:07):

I also don't think the way Haskell uses _ at the end of names is a convention Roc should adopt. :big_smile:

view this post on Zulip rudolf (Dec 30 2023 at 15:57):

Richard Feldman said:

I also don't think the way Haskell uses _ at the end of names is a convention Roc should adopt. :big_smile:

Of course, that wouldn't make sense for Roc. I just pointed out that one example is to differentiate two similar functions.

But the main reason for me is that if I'm working with an outside world that is completely snake case, I want to be a snake case too or otherwise it's distracting and error-prone.

view this post on Zulip geor (Dec 30 2023 at 17:39):

Richard Feldman said:

I'm curious - what specific use cases do you want it for?

doIt_ will be a helper function for a function doIt. The trailing underscore means I don't have to come up with a name (like doItHelp) and I shouldn't expose it since it is a helper.

But most importantly, everything I do is snake case. And I understand that Roc code should be camelCase but if I'm writing something just for myself and not open-sourcing I want to use the same casing as all those JSONs I'm working with have or the Python code I'm trying to convert to Roc uses.

I didn't realize how it is :firecracker: :firecracker: :firecracker: (pardon my French) annoying when I'm forced to use camelCase for my private projects. I love Roc but this small aspect wants me to break my keyboard.

Apologies for this non-pragmatic answer. I love what you do Richard.

view this post on Zulip Richard Feldman (Dec 30 2023 at 18:36):

I hear what you're saying, but I have to admit I'm really surprised. Personally if I'm using a language where the standard library and ecosystem is camelCase, then I use camelCase, and if it's snake_case I use snake_case. Otherwise my code inevitably ends up being a mix of both.

This is the first time I've ever heard of a preference for mixing snake case and camel case in the same code base being an explicit goal!

view this post on Zulip geor (Dec 30 2023 at 20:12):

You know, it would be nice to have the option ;-).

view this post on Zulip Chris Wesseling (Dec 31 2023 at 10:13):

Hi, just dropped in. From most of this I get the same feeling I had when I started to use Python. I always used tabs to indent because it takes only 1 byte and everyone gets to set their own tabspace to their liking. So I kept using tabs. Used "having the option" to do so. But the moment I started working with other codebases, it bit me and I wished I wasn't as change averse over something invisibly small. To the point that I expect to have a formatter to do it for me.

JSON is just the message format. I'm working in Python with prescribed camelCase OpenAPI specs, but in the code all data is represented with snake_case keys, and we deal with the differences between our models and the data interchange at the edge; the (de-) serialisation step.

That said. When I implement a paper, I often wish I could use greek letters and prime characters as names in my program. The literature often has come to some common notation. And juggling the new concept is already taking precious cognitive load, so having the same notation would relax some of that. The way Python used to be very close to pseudo code in notation.

But then again, papers are to code as JSON is to code. A message that needs to be translated.

view this post on Zulip Alexander Pyattaev (Jan 01 2024 at 19:44):

My 50c to this - if _ is not valid in variable names, the compiler should tell me as much. Instead I am greeted with this:

❯ roc repl

  The rockin' roc repl
────────────────────────

Enter an expression, or :help, or :q to quit.

» x_1 = 4
thread 'main' panicked at 'not yet implemented: handle pattern other than identifier (which repl doesn't support)', crates/repl_ui/src/repl_state.rs:123:25
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

This is the opposite of friendly. I'd say rust is doing it right where it allows you to use whatever names, but annoys you with warnings that you can silence if you want (e.g. to match variable names to definitions in a spec or to keep them consistent across languages).

view this post on Zulip Brendan Hansknecht (Jan 01 2024 at 19:49):

For sure. We have a lot of cases where we need to fix up and improve error messages

view this post on Zulip Brendan Hansknecht (Jan 01 2024 at 19:49):

Logging issues as you see things like this is always nice

view this post on Zulip rudolf (Jan 02 2024 at 09:49):

Anton said:

to `if ch.is_alphabetic() || ch.is_ascii_digit() || ch == '_'

I tried this mainly to get familiarise myself with the Roc code base. I made this change in 3 places - for a module, highlighting and the rest. And it works - including the language server.

I'm not sharing the result since it is very easy to make the change and also this is not an officially approved patch.

Thank you @Anton for sharing.


Last updated: Jul 06 2025 at 12:14 UTC