And more importantly, I don't think there's any JEP trying to improve checked exception handling.
197 karma · joined April 26, 2025
And more importantly, I don't think there's any JEP trying to improve checked exception handling.
> I'm a VSCode user and when I hear people talk about neovim and it customizability
I think it's more customizable than vscode, but you need to learn some lua or vimscript to customize it. Back then I tried to create some custom keybindings in vscode and realized you can't add new ones, only modify what exists. While (n)vim provides you with out-of-the-box flexibility and more if you use something like LazyVim. > Is it because it's faster?
What I retroactively like about (n)vim is that, after the initial learning cost, it turns out the default nvim keybindings are transferable to many UNIX tools (less/more, man, journalctl, etc). It feels much more comfortable to write some code in nvim, open up a terminal, and then `man X` without mentally switching the keybindings. > Maybe it's because it's an editor you can easily use while ssh'd into a remote machine?
Actually, rather than nvim itself, it's more like vim is already preinstalled in many popular server distros. It's sometimes a huge time saver in cases where you're unable to install additional packages to edit some config/code/text files, just type `vim`/`vi` and you're good to go.I did convert myself from a minimal vscode setup (disabled everything & only LSP extensions) to LazyVim nvim a few months ago. I had to tweak my .config/nvim, relearn Lua again, and read the manual. It took me about a week to settle things down and get used to basic nvim bindings.
After another week of suffering trying to fix JDTLS (Java LSP) integration, I'm enjoying my nvim setup. Unlike vscode sync which requires you to login, I could just git clone my `.config/nvim` and I'm good to go.
This reminds me of recreational math & gamedev, you simply do whatever you feel is fun and design it exactly as you'd like it to be.
> Of course, in both languages you can write unidiomatically, but that is a great way to ensure that bugs get in and never get out.
Why does "unidiomatic" have to imply "buggy" code? You're basically saying an unidiomatic approach is doomed to introduce bugs and will never reduce them.It sounds weird. If I write Python code with minimal side effects like in Haskell, wouldn't it at least reduce the possibility of side-effect bugs even though it wasn't "Pythonic"?
AFAIK, nothing in the language standard mentions anything about "idiomatic" or "this is the only correct way to use X". The definition of "idiomatic X" is not as clear-cut and well-defined as you might think.
I agree there's a risk with an unidiomatic approach. Irresponsibly applying "cool new things" is a good way to destroy "readability" while gaining almost nothing.
Anyway, my point is that there's no single definition of "good" that covers everything, and "idiomatic" is just whatever convention a particular community is used to.
There's nothing wrong with applying an "unidiomatic" mindset like awareness of stack/heap alloc, CPU cache lines, SIMD, static/dynamic dispatch, etc in languages like Java, Python, or whatever.
There's nothing wrong either with borrowing ideas like (Haskell) functor, hierarchical namespaces, visibility modifiers, borrow checking, dynamic dispatch, etc in C.
Whether it's "good" or not is left as an exercise for the reader.
Not sure why many people seem fixated on the idea that using a programming language must follow a particular approach. You can do minimal alloc Java, you can simulate OOP-like in C, etc.
Unconventional, but why do we need to restrict certain optimizations (space/time perf, "readability", conciseness, etc) to only a particular language?
It's a hard sell for me, considering Factorio has a ton of actively developed mods (cough Space Exploration 0.7 cough), a demo, and in early access era it's cheaper and insanely polished.
From a quick glance, I'm not sure whether it's a fun game or not, as realism tends to be not fun. Requiring an internet connection for map tiles also sounds not good for offline play.
Well, I'll wait for reviews when it's out before deciding then.
Reflection is what makes DI feel like "magic". Type signatures don't mean much in reflection-heavy codes. Newcomers won't know many DI framework implicit behaviors & conventions until either they shoot themself in their foot or get RTFM'd.
My pet theory is this kind of "magic" is what makes some people like Golang, which favors explicit wiring over implicit DI framework magic.
> Just don't write bad code
Reminds me with C advices: "Just don't write memory leaks & UAF!".It's a good example for the "Parse, don't validate" article (https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...). Instead of creating a function that accepts `int` and returns `int` or throws an exception, create a new type that enforces "`int` less than equal 200"
class LEQ200 { ... }
LEQ200 validate(int age) throws Exception {
if (age <= 200) return age;
else throw Exception();
}
LEQ200 works = validate(200);
// LEQ200 fails = validate(201);
// LEQ200 hmmm = works + 1; // Error in Java
LEQ hmmm = works.add(1); // Throws an exception or use Haskell's Either-type / Rust's Result-type
Something like this is possible to simulate with Java's classes, but it's certainly not ergonomic and very much unconventional. This is beneficial if you're trying to create a lot of compile-time guarantees, reducing the risk of doing something like `hmmm = works + 1;`.These kind of compile-time type voodoo requires a different mindset compared to cargo-cult Java OOP. Whether something like this is ergonomic or performance-friendly depends on the language's support itself.
I am an occasional uni TA that teaches OS and I use littleosbook as the main reference for my own project guidebook.
It's a decent warm-up project for undergraduates, giving them a first-hand experience programming in a freestanding x86 32-bit environment.
I'm not sure I'm following with the article, I don't think there's much of a problem treating `java.util.Optional` as a `Maybe`-like.
Regardless of "monad" label, it does work ok at modelling a container with [0..1] element and provides `Functor` fmap + `Monad` bind to operate the values.
Looking at `Omittable` APIs, I don't think there's much difference with the latest `java.util.Optional`? Why should I pick `Omittable` over standard library `Optional` then?
Personally, I roll my own "header-only"-style `Nilable<T>` on personal repo. I like to merge `orElse` and `orElseGet` into a single overloaded `orElse`, turning it to bare `null` resistant due to deliberate ambiguous method resolution.
Curiously none of 3rd party `Option`-like JVM libraries have this behavior, so I had to make it myself.
> But now string literals are “untrusted”. So you have to do new String(“this is trusted content”) everywhere you need it, which is a pain.
Eh? Isn't that the main point of doing all of this? Being explicit on the boundaries but still providing a way to manipulate them like a String?I don't see anything wrong with `new Validated("literal")` (or functional friendly `Validated.of("literal")`). If you intend to create a `Validated`, then create it via constructor / static factory method that enforces necessary validations to create `Validated`.
> So you have to live with that, or make overrides for every single string function that fix the types where necessary.
Like `Optional<T>` and `Stream<T>`, you could define `Validated::map(Function<? super String,String>)` if you want. With `map()`, you could operate `Validated` with anything that accepts `String` like usual.With that said, I don't recommend using `Validated` in your actual Spring project though, use (OOP) value objects instead. I used value objects quite a lot on my legacy Spring project. It plays nicely with functional-style, cover "validation" stuff, and avoiding primitive obsession. Putting `String` on `UserId` will result in a loud compiler error.
But GP described something they wanted from a type system and basically said container with `Functor`-like behavior is not possible to do in Java. It's possible, albeit with a performance drawback and a bit more clunky to work with compared to Rust, Haskell, or a language with native HKT support.
It's more like "comptime safety feeling" => "language w/ visibility modifier" but the converse is not necessarily true. Without language support, it's back to C convention or workaround again.
Though it reminds me of Alexis's "Parse, don't validate", isn't `syscall :: u8 -> Untrusted<u8>` considered as "validate"?
I hope kernel codes that consume it will transform it to appropriate type as well `Untrusted<u8> -> T`.
The main problem with ADT is language support for them. Primarily sum types, as they're missing in a lot of major PLs, while product types are "just" structs or classes.
Without language support, you can simulate them via brittle workarounds like `if (d.isTypeA()) return d.methodA()`.
Actually, I agree, it is mundane. That's exactly why it's kind of becoming an itch for anyone used to ADT, you'll feel like you're missing a basic building block.
Just imagine if all languages removed `struct`-like and `class`-like construct. Something like Brainfuck esolang or any plain asm. It certainly possible to create arbitrary complex program in those languages. But would you pick `struct`-less language over language that supports it natively?
I think you're confusing ADT with a Typescript-like type system. Adding language support for ADT is not really a warrant for an "enough DOF to become scary" sticker.
I find modern Java surprisingly pretty good at capturing the essence of ADT without introducing way too much fancy stuff. Modern Java supports ADT via `sealed` classes (sum types) and `record` (product types). For working with ADT classes, modern Java provides exhaustive `switch` expression and `record` destructuring.
That's enough for minimal "language ADT support". You still can't do Typescript's wacky operations like conditional / mapped types or type parameter recursion in Java. You can't do fancy Haskell's typeclasses here either. And it is certainly not turning Java's type system into a Turing-complete type system at all.
Eh, I don't think Java type system is strict, nor is it the root cause of this cargo cult mess. It's probably due to many enterprise programmers who think design patterns are the building blocks of everything rather than an invisible, emergent structure.
Pretty sure it's a self-destructive move for a CS or software engineering student to pass foundational courses like discrete math, intro to programming, algorithm & data structure using LLM. You can't learn how to write if all you do is read. LLM will 1-shot the homework, and the student just passively reads the code.
On more difficult and open coursework, LLM seems to work pretty well at assisting students. For example, in the OS course I teach, I usually give students a semester-long project on writing from scratch x86 32-bit kernel with simple preemptive multitasking. LLM definitely makes difficult things much more approachable; students can ask LLM for "dumb basic questions" (what is pointer? interrupt? page fault?) without fear of judgement.
But due to the novelty & open-ended nature of the requirement ("toy" file system, no DMA, etc), playing a slot machine on LLM just won't cut it. Students need to actually understand what they're trying to achieve, and at that point they can just write the code themselves.
But I think promoting profilers is much more important than debuggers. Far too many people I know are too eager to jump on "optimization" just because some API is too slow without profiling it first.
Vscode (or an editor with ADP support) supports unconditional breakpoints, watchpoints, and logpoints (observe & log values to the debug console).
I mean, don't get me wrong, I do agree engineers should at least be aware of the existence of debuggers & profilers and what problems they can solve. It's just that not all the stuff you've said belongs in the "must know" category.
I don't think you'll need valgrind or query planning in web frontend tasks. Knowing them won't hurt though.
Those bosses felt way too frustrating to me because they force you to unlearn the entire deflect gameplay, turning it into an annoying, slow-paced & somewhat janky fight.
> I do not understand your argument about branches, how would it hinder the jump instructions?
Extra set of logic for handling NaN cases? I don't think it's impossible, just kind of less intuitive. Jump instruction using integer w/o NaN always valid, while NaN-able integer sometimes invalid (ignoring whether the memory address can be accessed).Also, this in-band signaling probably would invite something similar to `null` mess in type systems. I can't wait to tell CPU to JMP NaN.
While "twos complement" turns the MSB unsigned value to a negative instead of a positive. For example, 4-bit twos complement: 1000 represents -8 (in unsigned 4-bit, this supposed to be +8), 0100 represents 4, 0010 represents 2, 0001 represents 1. Some more numbers: 7 (0111), -7 (1001), 1 (0001), -1 (1111).
Intuitively, "ones complement" MSB represents a multiplication by (-1). While "twos complement" MSB adds (-N), with N = 2^(bit length - 1), in case of 4-bit twos complement it's (-2^3) or (-8). Both representation leave non-MSB bits work exactly like unsigned integer.
Say we have a perfect "make illegal states unrepresentable" model. Like what you said, it's kind of inflexible when there are requirement changes. We need to change affected codes before you can even proceed to compile & run.
On the other hand, an untyped system is flexible. Just look at Javascript & Python ecosystem, a function might even contain a somewhat insane and gibberish statement, yet your program might still run but will throw some error at runtime.
Some bugs in programs like games or average webapp don't matter that much. We can fix it later when users report the bug.
While it's probably better to catch whether an user can withdraw a negative balance or not at compile time, as we don't want to introduce "infinite money glitch" bug.