Rendered at 21:52:51 GMT+0000 (Coordinated Universal Time) with Cloudflare Workers.
tananan 9 hours ago [-]
I generally work on internal-use Python codebases. I would much rather do some basic validation and fail loudly if anything I didn’t account for happens.
One of the issues I run into is that agents are predisposed to write extremely defensive, odd-case-handling code, and that makes me recoil when I have to look into it: the SNR ratio is very low. You get a spaghetti that is unlikely to crash, but really hard to extract the gist of. And finding more global bugs can be difficult because what should be structural impossibilities can be coerced into silent skips.
The article made me think that maybe what I’d like is a language where validation doesn’t triple the lines of code you have to write.
gumby 6 hours ago [-]
> …agents are predisposed to write extremely defensive, odd-case-handling code… the SNR ratio is very low. You get a spaghetti that is unlikely to crash, but really hard to extract the gist of. And finding more global bugs can be difficult because what should be structural impossibilities can be coerced into silent skips.
Have you tried asking for a summary of the logic being relied on, and asking LLM to simplify the code?
I’m 85% joking, of course, given the current state of automated code generation and the terrible summaries you usually when asking for a summary of text. But in theory that’s what they are supposed to do.
middayc 9 hours ago [-]
I agree, if you don't have a clear view on what you want to do on certain exception, or you are adding information or translating/wrapping error into a higher level one, then it can be cleaner to let program fail naturally in that specific case. Catch, print error and panic makes no sense in many cases and can make the exception less clear when it happens.
mike_hock 9 hours ago [-]
Yeah, or just let the exceptions bubble up and the boilerplate goes away.
middayc 9 hours ago [-]
But sometimes you must act on exceptional situations, recover, take alternative route, provide default, or translate exception from lower level one to a higher level one. From cause based to more intent based. Err, file not found setup.txt -> Couldn't read your setup -> ...
Which its great if this also doesn't loose lower level information, but just wraps it, so end user could dig into the error.
mike_hock 8 hours ago [-]
> But sometimes you must act on exceptional situations, recover, take alternative route, provide default
And then the Rye version is presumably just as verbose.
> or translate exception from lower level one to a higher level one
This is the actual flaw in exception-based languages. Adding context should be much more convenient.
middayc 8 hours ago [-]
Then the rye code "needs more meat" too yes, but not that much changes, |fix { code } already does the fixing and provides an alternative, |^check { failure construct dialect }, already wraps received failure into a new one you construct, and exits to caller. There are other such functions but these two are most common.
Additional benefit I see, they already express intent. Like map, filter, reduce express intent better than foreach loop.
middayc 10 hours ago [-]
I'm the author. If anyone has any feedback, you are welcome ...
broken-kebab 9 hours ago [-]
The idea looks elegant!
The only thing so far which feels not fully fitting is that dot and pipe are often semantically equivalent - applying function to the output of the previous one. And yet you still need to pick the right one.
E.g. Clojure (which is too hosted over OOP language) treats dot as an indicator that it's a method, but invocation/application follows the same syntax as any fn:
(.method (function arg))
Meanwhile in Rye:
"12 8 12 16 8 6" .load .unique .sum
when unique and sum are from underlying Golang, but if I made them myself it suddenly has to be:
12 8 12 16 8 6" .load | unique | sum
middayc 9 hours ago [-]
Thanks! But words with dots vs. Pipes dont work that way.
All functions, user level or builtins (written in Go) (or generic methods that dispatch on the Kind of first arg) have exactly the same calling conventions/rules. Dot vs pipe is a matter of evaluation priority, that works the same on all of them.
One of the issues I run into is that agents are predisposed to write extremely defensive, odd-case-handling code, and that makes me recoil when I have to look into it: the SNR ratio is very low. You get a spaghetti that is unlikely to crash, but really hard to extract the gist of. And finding more global bugs can be difficult because what should be structural impossibilities can be coerced into silent skips.
The article made me think that maybe what I’d like is a language where validation doesn’t triple the lines of code you have to write.
Have you tried asking for a summary of the logic being relied on, and asking LLM to simplify the code?
I’m 85% joking, of course, given the current state of automated code generation and the terrible summaries you usually when asking for a summary of text. But in theory that’s what they are supposed to do.
Which its great if this also doesn't loose lower level information, but just wraps it, so end user could dig into the error.
And then the Rye version is presumably just as verbose.
> or translate exception from lower level one to a higher level one
This is the actual flaw in exception-based languages. Adding context should be much more convenient.
Additional benefit I see, they already express intent. Like map, filter, reduce express intent better than foreach loop.
The only thing so far which feels not fully fitting is that dot and pipe are often semantically equivalent - applying function to the output of the previous one. And yet you still need to pick the right one.
E.g. Clojure (which is too hosted over OOP language) treats dot as an indicator that it's a method, but invocation/application follows the same syntax as any fn:
(.method (function arg))
Meanwhile in Rye:
"12 8 12 16 8 6" .load .unique .sum
when unique and sum are from underlying Golang, but if I made them myself it suddenly has to be:
12 8 12 16 8 6" .load | unique | sum
All functions, user level or builtins (written in Go) (or generic methods that dispatch on the Kind of first arg) have exactly the same calling conventions/rules. Dot vs pipe is a matter of evaluation priority, that works the same on all of them.
In fact there are more word types in that "game", words, dotwords, opwords and pipewords :) look here for more: https://ryelang.org/meet_rye/specifics/opwords/