230 karma · joined July 4, 2025
Tomayto Tomahto.
> I have seen many Rust programs in my day, and not a single one has ever used `catch_unwind`
Yeah, cause it sucks. Hence my original point: all downsides and no benefits. Also how people use Rust's exceptions has no bearing on whether or not they are exceptions.
> The fact that unwinding can be (and regularly is) trivially disabled is the ultimate motivator of why panics fundamentally cannot be used for error handling
Unwinding can be disabled in C++, too. They still call them exceptions over there.
> you appear to misunderstand the purpose of destructors.
In a language with exceptions, destructors (or something similar like try-finally) are required to guarantee resource cleanup. In a language without exceptions, it is enough to simply write the cleanup code at scope exit points. Rust's static analysis is strong enough to ensure you do this correctly in the hypothetical world where the language does not have exceptions.
If your insinuation here is that I don't understand why you might still want destructors in the absence of exceptions, then you've missed my point.
> Feel free to provide code if you would like to try to make a more precise argument against unwinding.
I already linked the precise argument against unwinding. It's written by Niko Matsakis, one of the core Rust language designers. It explains both the "temporary move from behind an exclusive reference" point and the "return a value from a drop impl" point (which the article calls "must move").
Polymorphism won't get rid of the 23 if statements, it will just replace them with 23 method implementations. Then when you try to serialize that "conceptual entity" to a file or network socket you'll yearn for the if statements once more.
The main benefit of polymorphism is that it allows you to modify one part of a program without recompiling the other parts. In the absence of pre-compiled modules, polymorphism is isomorphic to branching/switch statements:
Clean Code is unhelpful to beginners too, though: misuse of industry-standard terms, shunning of comments in favor of tiny functions with long names, shunning function arguments in favor of mutating state, polymorphism obsession, etc. So much of the concrete advice the book gives is just plain bad.
The reason people get more pissed off at Clean Code than they would at any other book that gives bad advice is the preachy and authoritative tone it uses. It frames people who don't do "Clean Code" as unprofessional and lazy, and this framing is very convincing to some people, as evidenced by some of the replies in this thread.
An example of failing to follow DoD is the N+1 query problem: a programmer builds an abstraction that operates on individual DB rows, but "where there's one, there's more than one": you will inevitably be running that code in a loop so that you can process multiple rows. If instead the programmer had abstracted over groups of rows, then per-item query overheads suddenly become per-batch overheads.
use std::panic::catch_unwind;
fn throws_exception(){
panic!("hello");
}
fn main(){
match catch_unwind(|| {
throws_exception();
println!("Never reached");
}) {
Ok(_) => (),
Err(e) => println!(
"threw an exception: {:?}",
e.downcast_ref::<&'static str>().unwrap())
}
}
I can disable exceptions in rustc, but I can't disable the influence they have on language and library design (as detailed in the link I posted). Exceptions are the main reason you can't temporarily move something out from behind an exclusive reference, or return an error code from a Drop impl. Heck, Rust wouldn't even need destructors if it weren't for exceptions: the compiler could just tell you when you forgot to free something.Again: I'm not disputing the fact that the rust index operator does a dynamic bounds check.
https://smallcultfollowing.com/babysteps/blog/2024/05/02/unw...
for i in some_arr {
println!("{i}");
}
I suspect most techniques you could think of to statically avoid bounds checks are possible in rust's type system.That's the thing, though. Your Fil-C code isn't calling mmap, it's calling the Fil-C wrapper for mmap. In neither Fil-C nor Rust('s safe subset) can you call the actual system mmap.
Someone in the audience also pointed out that a tool like this could be used to compile rust programs, not just C programs, in which case it's odd to hear Fil-C repeatedly framed as a language in opposition to rust rather than as a tool which might complement it.
I'm complaining on these developers' behalf, not bemoaning them doing what they were more or less forced to do. If glibc decided tomorrow to remove the `malloc` function from their library and every C project suddenly had to implement its own allocator, that would be a massive waste of everybody's time, no?
I'm also going to hesitantly mention sveltekit. From the outside it looks like yet another JS front-end framework but having been forced to use it recently I've learned it actually has great support for the more hypertext-focused design philosophy promoted by HTMX and friends.
- Effort spent writing sway that could have been spent improving i3
- Effort spent writing GNOME-Wayland that could have been spent improving GNOME
- Effort spent writing KDE-Wayland that could have been spent improving KDE (much of this work duplicated effort with GNOME-Wayland)
- Effort spent writing wlroots to try and mitigate the effort being wasted by people writing bespoke compositors
- Wine/Proton devs needing to waste time getting every windows application to work in Wayland
- Firefox needing to target both Wayland and X
- A bunch of graphical toolkits and window managers that were working perfectly fine but will now be "left behind" since they lack the maintainers to support a porting effort
- low-level toolkits like SDL needing to implement their own window decorations now that they're not guaranteed to be provided by the OS (what?!)
What Wayland proves to me is just how easy it is for a small number of developers to unintentionally sabotage productivity in a much larger project.
https://anubis.techaro.lol/docs/admin/configuration/challeng...
I guess for the meta refresh challenge it's less "proof of work" and more "proof of patience".
https://www.gnu.org/philosophy/javascript-trap.html
Users can't consent to running a page's javascript the way they can consent to running a program they've intentionally downloaded, so it's effectively "non-free" regardless of license.
function initWidget(root){
// Or a bunch of calls to document.createElement, whatever you want.
const inp = root.querySelector('.input');
const check = root.querySelector('.check');
function update(){
inp.style.display = check.checked ? 'none' : 'block';
}
check.onchange = update;
}
> O, but not when this checked, etc. function initWidget(root){
// Or a bunch of calls to document.createElement, whatever you want.
const inp = root.querySelector('.input');
const check = root.querySelector('.check');
const check2 = root.querySelector('.check2');
function update(){
inp.style.display = check.checked && !check2.checked ? 'none' : 'block';
}
check.onchange = update;
check2.onchange = update;
}
Compare to React: function Widget(){
const [check1, setCheck1] = useState(false);
const [check2, setCheck2] = useState(false);
return <>
<input type="checkbox"
checked={check1} onChange={e => setCheck1(e.target.checked)}/>
<input type="checkbox"
checked={check2} onChange={e => setCheck2(e.target.checked)}/>
{check1 && !check2 && <input type="text" />}
</>;
}
Compare to Svelte: <script>
let check1 = $state(false);
let check2 = $state(false);
</script>
<input type="checkbox" bind:checked={check1}>
<input type="checkbox" bind:checked={check2}>
{#if check1 && !check2}
<input type="text">
{/if}
IME almost none of the complexity in any of the web applications I've worked with has been mitigated by the front-end framework in use. You still need to write the code to do the thing, whatever that thing is. You might as well write it in the framework that gives you the smallest bundle size and the best possible backwards compatibility, and that's vanilla JS + the standard web APIs.The perf argument against RAII is very abstract and is less "RAII causes bad performance" and more "the kind of design that leads you to reach for RAII is the kind of design that's bad for performance." There exist similar hand-wavy arguments against many other C++/Rust features.
More generally, "you shouldn't even want that" is basically a meme at this point in programming language design. Every new-ish language has some version of it.
https://en.wikipedia.org/wiki/Loop_invariant
You should think of it as the condition that's true for all iterations, not a one-time event that halts the loop. The loop is short for this:
for(size_t i = size - 1; 0 <= i && i < size; i--){
}
Which works for both signed and unsigned numbers. It just so happens that for unsigned numbers you can omit the left-hand side of the &&, and for signed numbers you can omit the right-hand side. To support arbitrary lower bounds, you omit neither.Again I'm not understanding the distinction. I don't need to run sudo commands to install a web server, and depending on your definition of "exposing something new" to the network then either I don't have to do that either or your solution also does that.
Something is getting downloaded and run on the remote machine, correct? Why is it problematic for that something to be a web server (with SSH-forwarding I guess) instead of this custom thing?
And why install anything on the server at all if it'll just serve a binary that downloads and runs on your local computer anyway? For example, if I type `sftp://username@server.domain/file/path` into my file manager's address bar, I get the nice file browsing experience you demonstrate without installing anything on my computer or the server.
EDIT: OK, after reading through your earlier posts, I think the value proposition really is just that you've implemented a slightly better UX for proxying remote web servers via ssh, and that the "run native code" thing is an independent idea you are also pursuing. So the answer to the question "isn't this just proxying an http server over ssh" is basically yes.
I think I incorrectly read this as attempting to propose a radically new idea and not as an incremental improvement to the status quo.
This sentence is bizarre to me. Your SSH-based solution also requires exposing a port to the internet and installing a special tool (on both server and client!). What's so special about SSH that using HTTPS is a problem but using SSH isn't?
The industry also tried the whole "use the web browser to run native binaries" thing with ActiveX (and the unity web player I guess). The idea was thrown out along with flash and java applets for what I presume were security and portability reasons.
IMO a good approach is to update the UI immediately but still show some indication that the operation hasn't completed. So in a chat app, for example, add the message to the list of messages, but with contrast reduced slightly to indicate that other people can't see it yet.
It is not. It tries to address async/await part-way through, but it does so without the context of 10 years of successful async/await usage in javascript, the language it's criticizing.
> Threads do solve this problem because they are just regular functions being called by other regular functions. They don't require the entire function stack to be `async` in order to work.
This is fixating on syntax: it would be trivial for all functions to simply be `async` by default and for all calls to an `async` function to automatically `await`. This might "fix" the coloring problem as you describe it but I argue wouldn't meaningfully change anything.
If async/await doesn't solve the coloring problem, then neither do threads. Why would you ever need to start a thread to invoke a function when you could just invoke the function directly? Because the function is a red function.