The numeric postfix fn thing is fun. I presume it'd be restricted to Frac|Int -> T signatures. I request that the type coercion functions are named u8, i64, etc instead of the to_...mentioned in the video.
We would definitely need to either have 12h desugar to 12.to_h(), or change Num.to_u8() and similar functions to Num.u8(). The latter option seems more confusing, we should probably keep the to_* prefix
the idea is for 12h to desugar to h(12)
so you can bring your own functions rather than being limited only to functions that are defined on Num already
e.g. if a graphics platform wants to use 12px
or a scientific computing one wants to do 12light_years or something
12USD
The problem is that 12u8 is easily readable, but the function name makes less sense outside of suffix usage
I'd like to still type 12u64 though
Because now Num.to_u8 is Num.u8
Karl said:
I'd like to still type
12u64though
I don't think we can reasonably have both
12.to_u8() or 12.u8() would be fine alternatives to 12u8 but if we're having 12h and 12u8 coexisting and meaning totally different things, that seems like a mistake
I thought the suggestion in the video was for 12u8 to now mean 12.to_u8() where 12 is Num *
no, the other way around
the idea would be that 12x now means x(12) always, unambiguously
Okay
which in turn means that 12u8 would mean u8(12)
yep
which in turn means we can't have that be the syntax anymore
Having u8 and friends as free functions isn't an option?
but if we have Num.to_u8 : Num a -> U8 then we can just have 12.to_u8()
I'd assumed Num would expose [u8, u16, etc.]
also fine
oh you mean like u8 and u16 are always imported unqualified by default in every module?
Yes, 12u8 can't be a syntax for numeric literals
not sure how much of a problem that would be
I'd rather not do that; currently we don't expose any values unqualified
I really don't think 12.u8() is a problem haha
Besides the plan to do that for True, False, Ok, Err
true haha
I guess those are different because they're tag names rather than variable names
It's fine, yep. Just pushing for consistent naming in the case we go with 12u8 means 12.u8() and 12h means h(12)
like we have variable names of u16 and such all the time
Yeah, it'd be a problem for any decoding impls
34 messages were moved here from #show and tell > roc-realworld initial exploration by Richard Feldman.
this might be a terrible idea, but maybe allowing like 1px + (x - 3)px could be a thing
a downside would be that at that point, ("a string")str_fn becomes valid :stuck_out_tongue:
well, or maybe it's an upside somehow, but it looks strange :sweat_smile:
No, it's probably a downside haha
given number types will unify automatically 27u8 doesn't feel too important as much as it feels proper.
we can special-case the method calls to do that though
like we can special-case 42.u8() behind the scenes the same way we special-case 42u8 today
404respond :stuck_out_tongue_wink:
How do we ban Agus /s
I'm not going to yell, but I'll register politely that I really don't like this.
the whole idea, or just using it in silly ways?
In a paren's and comma world does this syntax have an advantage over just doing px(27)?
Like just really minor looks, right? Not really less verbose or better for any specific use.
I think the main downside is that you’d get a really confusing error if you forget a space somewhere after a number
Like what is this px function doing?
We should be able to just add a CalledVia variant for UnitSuffix
Creating a Custom Type?
Yeah, maybe also converting units. At least that is the expected use.
I'd rather see Px(1) + Px(x - 3)
Something like https://github.com/Hasnep/roc-units I’d imagine
or the lowercase equivalent
I'd imagine you'd just expose the units you want with the nice abbreviations you like and then just call them
Not to be too dramatic, but I think this is like Perl/Raku-level magic
And the syntax is only for literals? Or literals and parenthesized expressions?
It's a little weird if you don't know what's happening, but it's just a function call of the suffix on the number. Seems really simple if you know what's happening
We couldn't do xpx where x is the var and px is the unit func, so no
Unless we allow (<expr>)suffix
I'm not going to die on the hill, but it seems little feature-cluttery to make a syntactic sugar for calling a function on a number literal
Which would open the door to postfix function calls, probably not a good idea
I'd like to see examples of abuse of this feature
I've seen it used correctly, but I don't look at much code in languages where this exists
1exit
LOLOLOLOLOLOLOLOL
You're very creative lmao
I think you'd make a good play tester :wink:
I think you could make a great package that parses expressions like this in Roc :smile:
expect Units.parse("1px + (x - 3)px", Map.empty().set("x", 15)) ?? Px(0) == Px(13)
the most generalized version of it would be saying you can call functions in either prefix or postfix style:
fn(arg1, arg2)
(arg1, arg2)fn
WWRD (What Would Raku Do?)
Richard Feldman said:
WWRD (What Would Raku Do?)
Be irrelevant outside of memes and Perl hardcores
Flame war incoming
Karl said:
12USD
It can even support the Cape Verdean escudo where they use the currency symbol as the decimal separator:
esc = \i -> \d -> Escudo (i + d / 100)
2esc(50)
I'll show myself out
@Agus Zubiaga 3 out of 6 messages in this topic from you are shitposts. I'm impressed
You were asking for ways to abuse it
I didn't know I was talking to a real-life genie
That said, these were useful examples to consider. Thank you
As for another language where something like this exists, Ruby (with a dot so 2.hours) is the obvious example with people monkeypatching their DSLs.
Nim loves syntax sugar and has optional paren free calls along with the x.foo(2) -> foo(x, 2) swap which does work on number literals so it can do 2.hours as well. I don't recall any specific abuse but I haven't spent a ton of time in the Nim community and there are much shinier toys for those inclined that way.
I believe it could be done with a reader macro in lisps that support them but I was always in the Scheme/Clojure subset which are reader-macro free.
Jokes aside, this doesn’t really seem to be a footgun. You can always abuse features to write terrible code, but I don’t think this encourages that.
I forgot! F# has an entire units of measure feature which looks like 12<cm>. I've seen that abused for currency which is why I did the 12USD above.
Why do you consider currency an abuse?
I don’t think it’s a stretch to call those a unit
The system is very much intended to be for units of measure. You can express relations between units, express 30<m/s> and so on. Currency isn't in the spirit of the system as a whole.
I do struggle to come up with an actual use for it, though
I don't think it caused any problems though.
Karl said:
Currency isn't in the spirit of the system as a whole.
what's the downside of that though? :thinking:
like if it's not error-prone and people like it, what's the problem?
Karl said:
As for another language where something like this exists, Ruby (with a dot so
2.hours) is the obvious example with people monkeypatching their DSLs.
this was specifically what I was thinking of - I think this is one of the things people find delightful about Ruby, and it's something I miss about programming in it
monkeypatching is not the way I'd want to get it, but an alternate function call syntax seems totally harmless compared to monkeypatching
I'm not going to condemn anybody for not using something in the way that's intended but I still consider it an abuse. I'm way further into the syntax sugar/metaprogramming spectrum than you all seem to be so I think this is fun.
and I don't see people doing 1.exit in Ruby even though they could :big_smile:
Well I doubt this would get abused (much), is it really enough of a gain to be worth using over px(27)?
it's totally fine to just use px(27) or h(12) or whatever (and I don't feel that strongly about the idea), I just find now + 12h more delightful than now + h(12) or now + hours(12) :shrug:
and very straightforward to explain etc.
Fair enough.
I think if we do this, it should only be for it literals and not expressions.
and numeric literals at that
100pct
I think Roc is best served by having the smallest set of primitives and any new one should have a STRONG justification
This doesn’t meet the bar for me
when I think about primitives, I'm usually thinking of things that have different semantics
not so much syntax sugar
although of course it is possible to go overboard with sugar, and more sugar also does carry the inherent downside of there being more than one way to do something
so there are definitely tradeoffs
Maybe I don’t live in the problem domains where this gives a big lift
And I’ve only seen this in languages with one or both of duck typed objects or getters/setters
Except F#. And I’ve never used that feature there or how it works
Here’s an article on it https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure
I feel like this wouldn't be that useful without proper unit support such that it can understand equations.
So you can do ft/s to to a feet per second variable.
In the current form suggested by this thread, it really can only unify to a single representation and do addition. Can't do multiplication or division which is fundamental for it to be useful for physics for example.
F# uses type wrappers and sugar that defines the relationship of units to one another
So not functions at all. Seems like they probably generate some methods and operator overloads for these types
In particular, I think you mean that we don't have heterogenous type overloading for math operations
You being Brendan
So you can only implement multiplication for one input (the custom type) and one output (maybe the custom type)
Yeah we can’t define add : Cm(I64), Ml(I64) -> Cm(I64) AND add : Cm(I64), Cm(I64)-> Cm(I64) , etc…
In the same module
we don't have heterogenous type overloading for math operations
yeah
C++ has something similar. I don't know how to define it there (is it a normal function, a class wrapper, a template, who knows...). But I've used std definitions of it. The two main ones are defining a string_view literal "hello"sv. But this is not a use case in roc.
However, the chrono header has a lot of these so you can define durations just like 200ms or 200s. This is a lot more ergonomic than rust's Duration::from_seconds. (Not speaking about all the things rust does better though :sweat_smile:)
Last updated: Jun 16 2026 at 16:19 UTC