HNHacker News
TopNewBestAskShowJobs

dfe

20 karma · joined January 15, 2024

submissionscomments
dfe··on AI Is a Mass-Delusion Event
Jim Acosta is a mass delusion event.
dfe··on It's a DE9, not a DB9 (but we know what you mean)
I'm a bit younger and I always called 0.1" spacing headers "Berg connectors" until the last couple of years when everyone started calling them DuPont.
dfe··on Endangered classic Mac plastic color returns as 3D-printer filament
I, too, am not the least bit nostalgic about the 486, Pentium, Pentium Pro, Pentium II, and later machines that I owned.

I think for me it's that they are too much the direct ancestors of current machines. There's basically zero software from that era nor any modern software written for these machines that really cares all that much about bus timings or cycle counting. It runs just as well or even better on modern machines in an emulator.

I'm not a big gamer, but even if I play later-1990s era EGA/VGA games on a modern PC, it feels basically normal to me.

I am nostalgic about machines older than that, particularly the mid-to-late 1980s machines that I grew up with. I now have decades of experience writing software. Even though I don't do much with hardware in my day job, I do know my way around hardware interfaces. I can read schematics and chip data sheets and know how to make it work. And what's nice about these machines is that many of them came with schematics and hardware register descriptions. Even if the paper is lost to time, someone has scanned them in and put them on the internet.

So I like to tinker with them. I like making them do things I wished I could do 35-40 years ago. I especially like when I can do it with pure software. Once such example is a DOS driver I wrote to make Tandy ROM drives accessible to (newer) non-Tandy DOS versions. https://github.com/dfelliott/tandy1000-romdrive

I had a 1000 TL I think I got probably late 1988 or early 1989. Back then I had a 40 MB hard card and it had to be partitioned because of DOS's 32 MB limit. When I upgraded to DOS 5 in 1991, literally going to the store the day it came out, I was dismayed to find I could no longer run Deskmate which was one of the main reasons to own a Tandy.

A few years ago I bought another one (my old one sadly bit the dust in a natural disaster) and went to work on fixing the problem. The journey was fun, and so was the end result. I finally got what I wanted, a machine running Deskmate and other software on DOS 5.

Coupled with my "sci-fi" Gotek I now have a machine that does a really good job of behaving like a machine of that era, because it is a machine of that era, running my old games with Tandy graphics and sound exactly how they ran back then. And I have real nostalgia for these games. There's something neat about what could be done with hardware of that era.

Emulation is just not quite the same. There's something about the CGA rasters on the tube that just feels right.

Plus, even though the machine bit the dust, I still have my old floppies, which I've started reading in with a Greaseweazle.

The Gotek doesn't really detract from the experience, it just takes away the drudgery of dealing with actual floppies and avoids wearing down what little is left of them.

dfe··on Six Days in the Dark
As someone who lived through a flood caused by a hurricane, without power for 10 days, I have first-hand experience with FEMA.

Some fat-ass government worker showed up with a tablet, checked a bunch of boxes on an electronic form to gather statistics on all the damage, gave us some information on government-backed loans, then left. This about 2 or 3 days after.

I will never forget how absolutely useless FEMA was.

dfe··on Use Long Options in Scripts
macOS doesn't have GNU coreutils at all. It has the utils from FreeBSD.

The gobsmackingly ancient GNU software it does have is bash, because it's the last version under GPL 2. I've used Mac OS X since 10.1, so I remember when the default shell was tcsh and /bin/sh was not bash.

That's (basically) the case again on the last few macOS releases. Today, zsh is my shell of choice, including on Linux.

dfe··on Why Every Programming Language Sucks at Error Handling
You can do this in a good Java debugger like IDEA. Break on the throw, unwind stack frames to your liking, hot-replace code, continue.
dfe··on Why Every Programming Language Sucks at Error Handling
I don't agree with the criticism of Java's exception handling, since Java literally does make exactly the distinction between "1. A Bug in the system" as RuntimeException, and "2. A faulty situation that can't be avoided" as all other Exception, particularly IOException.

Although the same statement is used to catch both, you only catch both if you catch Exception. If you catch IOException or whatever other exceptions you need to catch and you opt to handle them, then RuntimeException will still propagate.

It is only a matter of understanding that this is the distinction, and writing the bodies of your catch blocks accordingly.

And if you are only writing a prototype, declare that it throws Exception, or if you can't, a catch (IOException ex) { throw new UncheckedIOException(ex); } really isn't that bad.

dfe··on The Oligarchs Who Came to Regret Supporting Hitler
Me too.

I’m sorry for folks who are genuinely fearful, but I think this fear is all a farce.

dfe··on The Sudoku Affair
I once wrote a Sudoku solver in SQL in an afternoon because I was playing a Sudoku (a very newb player at that time) and it spontaneously occurred to me that all I was doing was a join or anti-join query repeatedly.

My data model was X,Y,V. Nothing nullable. Separately you need a table (possibly generated on the fly) of range 1 to 9. You wind up joining that a lot.

The whole program consisted of running INSERT INTO ... SELECT ... in a loop until 0 rows were inserted, indicating you were either done or you hit a point where no cell had a single solution. I'll spare everyone the rest of the details.

Incomplete, I know, but it fired the neurons, particularly with respect to the utility of the EXISTS expression in SQL.

I had no idea about things like "naked pairs" at that time, but I'm sure I could extend it to suport that.

It's interesting that if I translate that to a more traditional language, I independently came up with what is a cousin to Norvig's solution. I sure don't have his background, in fact my background is probably closer to Jeffries.

The main difference is that Norvig pre-enumerates all 9 possible values for all 81 cells then sieves them out, whereas my SQL constructs the 9*4 matrix from a temporary range 1..9 table, discovers the "must be" values, inserts those, then just repeats the process. Basically I'm Map<Coordinate, Integer> whereas Norvig is Map<Coordinate, Set<Integer>> and the algorithm is slightly different.

My experience agrees with the author's. Incremental design does not work. Prototyping and being willing to throw away your prototype and do something wildly different has always been the better approach in my experience.

You wouldn't believe how many less experienced engineers I help with problems by coming in and approaching the problem with a fresh set of eyes. It takes years to build the skill and willpower to incinerate days or weeks worth of work in favor of an alternative solution you can write in an afternoon. But it's not a waste! If you gained enough insight from doing it the wrong way to be able to write it the right way, then you maximized the value of your time. It is actually a waste of your time to keep iterating on a fundamentally flawed design.

dfe··on A better (than Optional) maybe for Java
I agree with you on your first statement. Exceptions for control flow is an awful API.

I also wholeheartedly agree with your comments that nullability should be a first-class language feature, part of the type system. I think what you describe is one of the active JEPs.

* Plain old String is "I don't know if it's nullable or not, so I'll let you dereference it without checking, but I may issue a warning.

* String! is "You're telling me it cannot be null so I will enforce that it is not null on the way in (e.g. when converting from String) and will issue no warning on the way out because it cannot be null.

* Finally, String? is "You're explicitly telling me it can be null, so I will force you to do a null check before converting to a String!"

But that's only part of it. I think Java desperately needs a ?. operator (Optional.map but without the Optional). I also think it needs a ?? operator (Optional.orElse but without the Optional).

So far I think Optional is more of a detriment to Java than a benefit. It feels like it was hacked in because without it some of the Stream APIs would be nightmarish given Java's current type system, and getting streams into the standard library API was too important a feature to wait for fixing the long-standing issues with nullability.

The only thing I disagree with you on is I do think there is some merit to checked exceptions when used sparingly. Capturing the idea that a method can fail for a reason that has to do with the program's input or environment (checked exception) vs. a reason that has to do with the program's code and cannot be solved without changing the program's code (RuntimeException) is a pretty neat thing.

I think the Streams API could have easily implemented terminal operations like forEach(ThrowingConsumer<E,X>). This could still be added.

I also think that the <X> ... throws X pattern should accommodate a union type like IOException|ParseException and that this should be inferred so that in this example of a throwing Consumer, whatever checked exceptions the method throws simply become the checked exceptions of the forEach method.

Conceptually, these are straightforward ideas. I suspect the limiting factor is figuring out how in the world to actually implement what I just described.

dfe··on A better (than Optional) maybe for Java
This seems to be worse in every way to Optional.

The throwing of a checked exception is ludicrous. It's a classic case of abusing checked exceptions for flow control. The right approach is an isPresent() or isEmpty() call followed by a get() when you know it's present. Static analysis can ensure you don't screw this up.

Similarly, using then and thenMaybe instead of map and flatMap means it now has its own terminology different from Stream.

Being able to iterate it is dubious. You can already .stream() an Optional (to an empty or 1-element stream). You can also if (o.isPresent()) { o.get(); } which is hardly burdensome. I'm trying to figure out how a for-each loop is an improvement. But if you must: o.map(Collections::singleton).orElse(Collections.empty()). Or o.stream().toList().

I applaud the author for experimenting with different API designs, but this one is just not good. It causes more trouble than it solves.

dfe··on A better (than Optional) maybe for Java
I used to think checked exceptions were stupid, so I'd catch and wrap them in a RuntimeException at the first opportunity just to get rid of them.

These days I've come around to your viewpoint that checked exceptions are great because all you have to do is declare them until you get to a point in the call hierarchy where you either can handle them or it's impossible to handle them so you wrap them.

In some cases, like with reflectively-invoked JUnit test methods, they only need to be declared because JUnit has its own exception handler. But you wouldn't believe the crazy amount of test code I see that eats exceptions instead of declaring them.

I think the confusion comes because with very simple programs you only ever see the point where you have to handle the checked exception, so a habit of writing catch blocks forms. It's only when designing libraries that you would declare checked exceptions as part of your method signatures and just allow them to naturally propagate. Therefore new Java programmers see all these extra catches and think it's just a burden they have to meet.

Another thing about Java that's bad for casual coding is that it exits 0 (success) when all non-daemon threads have ended, even if those threads ended because of an exception. It would be really nice if there was some internal flag set by the default uncaught exception handler that would cause a non-zero exit later when all threads are finished (which might be right then). Maybe I should submit a JEP.

dfe··on ELKS: Linux for 16-bit Intel Processors
Sort of.

It’s merely a ROM drive implemented in the BIOS. Drive 8 is used.

There’s also an INT 18h hook that operates by simply booting drive 8. This is the fallback bootstrap hook. No disks? No problem. Boots to DOS vs. IBM which booted BASIC or everyone else who just prints an error.

On one of these Tandy’s, DOS is really running from RAM, it is merely loaded from ROM, and even then it’s just a virtual disk.

I wrote a little tool to make the ROM drive accessible on non-Tandy DOS: https://github.com/dfelliott/tandy1000-romdrive

There are versions of DOS that can be run directly from ROM, but this isn’t one of them.

Curiously, Deskmate runs from ROM for real. Meaning the code is actually running in the Exxx segment backed by the actual ROM chip. The Deskmate files on the ROM drive are relatively small and are only a small part. The bulk of the code runs direct from ROM.

dfe··on 86Box: Emulator of x86-Based Machines
In the absence of VM extensions, which the earliest AMD64 CPUs did not have, once the CPU is in long mode, the base address of segments other than FS and GS doesn't work, it must be 0.

That's not such a problem for 32-bit segments whose base is normally 0 anyway (flat 32), but most 16-bit protected mode Windows code expects the linear address of its code and data segments to be something other than 0, and even might expect to be able to use multiple data segments with different base addresses.

So, sure, you can run 16-bit protected mode code with a base address of 0, but that's not very useful.

Also there's no virtual 8086 mode when in long mode to support real mode code.

With VM extensions it's possible to virtualize the CPU in regular (not long) mode, at which point the virtualized CPU will indeed support non-zero segment base addresses and virtual 8086 mode.

In theory this can be done with an extremely light virtual machine layer, but the entry/exit to/from the 16-bit code, or even for that matter any code needing to use 16-bit data segments is going to require more than it would if the CPU weren't in long mode. And this is assuming you have virtual mode extensions. If you don't then you need a CPU emulator.

My guess is that Microsoft felt it just wasn't worth writing all of this extra code needed to do this. There's a big difference between technically possible and makes even remote economic sense to do it.

dfe··on Tell HN: John Friel my father, internet pioneer and creator of QModem, has died
Just the other week I dug out my old Qmodem floppies, and I installed it on my retro Tandy 1000 TL. I used it with a null modem cable and USB serial to my Mac, where using something simple like picocom let me send files back and forth with Zmodem.

The built-in serial on this machine is too slow to be seriously useful (max sustained speed is 9600), but it was enough to send different network drivers to try without having to play with disk images and plug/unplug USB sticks from my floppy emulator to my Mac.

Qmodem was as familiar and useful as ever.

dfe··on Making memcpy(NULL, NULL, 0) well-defined
I once spent hours if not days debugging a problem with some code I had recently written because of this exact optimization.

It wasn't an embedded system, but rather an x86 BIOS boot loader, which is sort of halfway there. Protected mode enabled without paging, so there's nothing to trap a NULL.

Completely by accident I had dereferenced a pointer before doing a NULL check. I think the dereference was just printing some integer, which of course had a perfectly sane-looking value so I didn't even think about it.

The compiler, I can't remember if it was gcc or clang by this point, decided that since I had already successfully dereferenced the pointer it could just elide the null check and the code path associated with it.

Finally I ran it in VMware and attached a debugger, which skipped right over the null check even though I could see in the debugger the value was null. So then I went to look at the assembly the compiler generated, and that's when I started to understand what had happened.

It was a head-slapper when I found the dereference above. I added a second null check or moved that code or some such, and that was it.

dfe··on DOS 4.0 Source Code Released Under MIT License
Correction. Glancing at some of the actual code, and also looking at the README.md seems to indicate this is in fact the IBM DOS 4.

For example, the src/BOOT/MSBOOT.ASM file has a revision history including 3.31 and has code for the 32-bit sector count.

But more to the point the src/CMD/IFSFUNC folder contains the code for the IFSFUNC.EXE which only exists on IBM DOS 4.

So it would seem that the pdf folder has absolutely nothing to do with the source code, it's just an archeological bonus.

dfe··on DOS 4.0 Source Code Released Under MIT License
Looking at the pdf folder, this is the "Multitasking MS-DOS" product which is not the same as the "DOS 4" that most people think of. That "DOS 4" is actually IBM Personal Computer DOS 4, the successor to MS-DOS/PC-DOS 3.3 (with > 32 meg filesystem support borrowed from Compaq DOS 3.31) and predecessor to MS-DOS 5. Microsoft did later, quite confusingly, also release an MS-DOS 4 based on PC-DOS 4.

This is not that. This is the road not taken, at least not by IBM and compatibles.

At the time, Microsoft assumed that DOS as we know it would never live past version 3. This was their idea of what DOS 4 should be. A new major version breaking strict compatibility. What we know as OS/2 1.x was originally named DOS 5, another new major "DOS" version breaking strict compatibility.

This Multitasking MS-DOS never took off except in niche applications, and OS/2 eventually got its own product name which is why there were then regular DOS releases 4 and 5 followed by 6 and eventually 7 become part of Windows 95.

dfe··on Oregon's New Right to Repair Law Bans 'Parts Pairing' Restrictions
It very well could be. Legal precedent would be against Oregon. Consider the California CARB (Air Resources Board). There is a specific carve-out in federal law allowing California to have mandates on cars sold in California.
dfe··on Sampling: What Nyquist didn't say, and what to do about it (2018) [pdf]
https://en.wikipedia.org/wiki/PCM_adaptor

It's very likely that the 44.1 kHz rate comes from the PCM adaptors that were designed to take PCM audio and convert it to something that a video tape recorder would accept.

I watched a YouTube a few months ago about these adaptors and the presenter did the calculations showing how the 44.1 kHz 16-bit sample rate lines up with the video fields. There was a valid engineering reason for this sampling rate.

However, the stories about one of the Sony executives having a particular piece of music in mind are true, and have to do with the diameter of the disk being enlarged compared to what Philips originally had in mind. By that time the bitrate was already decided.

I still agree that 48 kHz is a better choice today, especially after reading this paper.

dfe··on A math professor who objects to diversity statements
I've been lurking on HN for years, and I just created an account to thank you for this post.

I always had this gut feeling that the Keynesianism in the aftermath of 2008 was a really bad idea but economics isn't my space and I don't care to argue with politicos about economics. This explains it really well.

So... now what?

← PreviousPage 2 of 2