Posted by lukastyrychtr 5 days ago
if you extend it to the most cursed ~6 lines of code, you really can obfuscate what you're doing in a way that's fiendishly hard to debug.
Seriously though, I love "abusing" programming languages in unexpected ways. My favorite so far is: https://evuez.net/posts/cursed-elixir.html. Reading this made me realize Elixir is literally macros all the way down, and it's a Lisp!
you still can create some more confusing things by idk. overloading some operators (but luckily not `=` and similar crazy C++ things) adding recursive macros and maybe combining it with lifetime variance and coercion edge cases, maybe sprinkle in some arcane `#[]` annotations and people with be very confused, more so then in the article
In Rust the return type of this function is the unit type, the empty tuple (). So, the variable has this type, there's no problem with this in Rust, even though some lesser languages can't handle the idea of a type this small.
Or did you mean a function which never returns, like std::process::exit ? In Rust this function's return type is ! the Never type, an empty type that you ordinarily can't name in stable Rust.
Because this type is empty, a variable of this type will evaporate, the compiler knows that we can't bring values into existence if there are no values of that type, the code paths in which this variable exists will never be executed, so no need to emit machine code.
In a language with generic programming like Rust this isn't an error, it's actually a convenience. We can write generic error handling code, and then for cases where there will never be an error our error handling code doesn't even compile, it evaporates entirely, yet for cases which can have actual errors, the error handling code is emitted.
because it doesn't compose well with generics, macros, proc-macros etc.
e.g. if you have this dump way to wrap clone: `fn foo<T: Clone>(v: T) -> (T, T) { let new = v.clone(); (v, new) }` it would implicitly not work with T = (), because then `v.clone()` would be a "function which returns nothing".
In isolation this might seem fine but if you compose abstractions you sooner or later run into an edge case where it isn't fine.
And this becomes even more a problem when macros/proc-macros are involved.
It also makes changing code easier, lets say you have something like `let x = foo(); dbg!(x);` and you change the return type it will keep compiling as long as the type implements `Debug`, even if you change the type to `()` (i.e. return nothing). And again for normal code that is a minor nit pick, but for macros, proc macros, generic code of sufficient complexity sooner or later you run into edge cases where it really matters that it's allowed. Not often but often enough.
Lastly and most importantly assigning `()` to a variable hurts no one, you won't see any such code in normal PRs.
So it it doesn't hurt anyone but can be quite use full in edge cases.
Lastly linters (mainly clippy) do warn or error for some of this nonsensical things, depending on the lint-set you enabled.