Hacker News new | past | comments | ask | show | jobs | submit login
If you're just going to sit there doing nothing, at least do nothing correctly (microsoft.com)
432 points by AndrewDucker 8 months ago | hide | past | favorite | 347 comments



I've learned this as "swallowing errors" and IMO it's a poor practice. Not only does it not solve the issue at hand (you cannot print on an xbox), but it actively hides how broken the software is, which makes bug discovery and testing much harder.

This is one thing I like about Go's panic. You're mostly not supposed to use it or recover from it at run time. It serves as a great vehicle to blare loud sirens at testing time that you (the programmer) screwed up (and that's ok, we all do), and it's time to figure out where and how to fix it :)

PS this analogy works in a lot of domains - If you have actors in a system actively trying to hide their flaws/errors it will be exponentially harder to root them out and solve the issues.


Error design depends on context. For most of the systems I work on, fail fast on request for anything out of spec is the correct design. B2B/Microservices/API focused systems. Windows however has focused on bending over backwards to provide compatibility (including memory patching popular software that was broken, like Simcity https://arstechnica.com/gadgets/2022/10/windows-95-went-the-... ). In the context of a user desktop where a user has no control of correcting the system code, the final experience is more important that correctness in many cases. It doesn't matter who is "in the wrong". Microsoft learned that it doesn't matter why the BSOD occurred, just that bad software/hardware was giving them the bad reputation.

So yeah, fail fast/halt catch fire on any invalid input/condition is my personal preferred design, but I can see the value in this approach in this environmental context. The important thing here is that context and not applying either dogmatically. Don't take Mr Chen's approach in reactor or HFT designs for example. Fantastic approach for game engines.


It's hard to overstate how hard Microsoft has worked to maintain backwards compatibility.

Recently I had to read an old Access file and where I work we still keep Office '97 around for this purpose and it is quite amazing that it installs and works just fine on Win 11, Clippy works just fine, in fact all the other lame-ass things Office '97 does to take over your desktop all still work even if they don't quite visually match the current desktop.

The thing is that Microsoft has a framework built into Windows where they can specify different system behaviors such as that Simcity case where the game didn't work with a new memory allocator so they put in a flag so an application that needs it can get the old memory allocator. They have a very systematic approach to the half-baked and haphazard process of patching the OS so you don't have to patch applications.


> It's hard to overstate how hard Microsoft has worked to maintain backwards compatibility.

Here's a pretty detailed list:

- It is possible to target Windows XP SP3 (released 2008, EOL 2014, 10 years ago) from Windows 11 and Visual Studio 2022[1] using C++23. Windows 2000 can be targeted with a little more setup[2]. Windows 2000 is 24 years old this year.

- It is possible to run a binary written for and compiled in Windows NT 3.1 x86 on a modern 2024 Intel/AMD PC running Windows 11 with absolutely no modifications to said binary whatsoever. Windows NT 3.1 is 31 years old this year.

- It is possible to write one binary and target multiple versions of Windows by simply choosing a Platform Toolset, which is paired with a Visual C/C++ Redistributable.

- Windows has a run-as mode to run programs in what is essentially a super-thin VM; like you mentioned, emulating different iterations' behaviour for a given program.

All four of these are nearly impossible on Linux. The fourth is essentially Docker, which is needed even to target an older glibc (i.e. the equivalent of the first situation). Windows has gone to extreme lengths to not only maintain API compatibility, but ABI compatibility as well. The fact that unmodified binaries from 20, 25, 30 years ago can run without a hitch is a testament to how important backwards/forwards compatibility still is on Windows.

Side tangent: all the criticisms levelled at Windows here and in many hacker fora are limited to its userspace—things like its shell and user-space programs, and trivial complaints like 'Candy Crush', or 'start bar', or 'extra right click', or even 'PowerShell aliased curl to Get-Content, grr'. The userspace changes so often because it can; it is a superficial part of Windows. To the haters: Try actually programming with NT OS primitives and even the (undocumented) NT syscalls. It is as enjoyable as UNIX system programming, and I daresay more productive.

[1]: https://learn.microsoft.com/en-sg/cpp/build/configuring-prog...

[2]: https://building.enlyze.com/posts/modern-visual-studio-meets...


I wish they included an 8086 emulator so that old software compiled for DOS would still run. It worked on 32 bit systems until 32 bit support was dropped, which only happened a few years ago. That was due to Intel's virtual 8086 mode, which is not available if your CPU is running in 64 bit (long) mode. Modern computers are fast enough for the emulation overhead to be negligible, even if you don't do any fancy JIT tricks and just go with a switch/case inside a while(true).

I would personally make use of this, I know of a 16-bit program whose latest version was released in the late XP days, so it's not even that old. The idea there was that it was always compatible with DOS, some users might presumably still want to run it on DOS, and there's no point in breaking that compatibility if modern Windows can run it just fine. Then development stopped, 64 bit systems got more popular, and a recompiled version was never released.

I guess the lesson there is that if you're keeping an API for backwards compatibility, some programmers will refuse to switch to a replacement to make their software work on older systems, making the API impossible to remove down the line without breaking modern programs.


At least you can still do this with third-party software like https://github.com/otya128/winevdm I guess? I imagine Microsoft doesn't see the returns for it to develop something they'll have to support for decades more…


This is great and all until you completely ignored the fact that wine exists and went on to call user space design questions by Microsoft “trivial”. I could also start listing ways that the Linux kernel maintains backwards compatibility with not just software but hardware that’s decades old but the list would get too long. No one is complaining that Microsoft has too much backward compatibility, it’s their utter disregard for user choices and privacy that drives away the hacker community to either Linux or even macOS.


Linux kernel on its own doesn't run software.


> Linux kernel on its own doesn't run software.

Linux runs /sbin/init.

Which you can make any executable you want.

Not to mention initial RAMdisk (loaded by a bootloader like grub) which can be of arbitrary size & loaded up with an arbitrary ton of goodness.


Yeah, which is quite far from a full OS experience providing ABI compatibility across several generations of operating systems.


Linux (kernel) has a userland ABI of its own. Which is pretty stable & rarely broken (Linus will probably breath fire @ any kernel developer who does break user space). So eg. 10y old statically compiled binaries will likely run fine on recent kernels.

But as you state: it's the OS-level ABI's (C library, desktop environments, middleware libraries, etc) that keep changing constantly. And thus, keep breaking pre-compiled binaries.

Source-level API vs. binary ABI stability. Kind of a philosophical debate imho. But sadly, even that source-level API isn't too stable in some circles.


Do you have an actual argument or are you really committing to "nuh-uh"


But it comes with drivers supporting very old hardware, hence the inclusion.


That alone still doesn't run applications.


application /= software. You're moving the (extremely ill-defined) goalposts. Next you'll be arguing that device drivers or the Linux VFS layer aren't "software".


The goal hasn't moved, we are talking about ABI compatibility for a full operating system across multiple decades and generations of operating systems releases, without requiring building those applications from source.

Not a kernel booting directly into an application doing straight syscalls.


GNU/Linux + the linux kernel.

Somehow, it feels like you don't actually care about the point I was making as much as putting me down. I misspoke...barely, yet you're so fixated on pointing it out in the most unhelpful manner. You keep replying so why not try using more than one sentence next time?


Now that you got there, which distribution released in 2023 allows me to run a GNU/Linux binary compiled in 2000, regardless of the distribution it was compiled on back in 2000?


If a binary from 2000 doesn't run, it's because of glibc ABI changes. I still have faint memories of glibc crap happening in the early 2000s. But if the binary from 2000 is statically linked, then the Linux kernel probably runs it fine today.

Which is weird considering the argument you had with others above about how "Linux (kernel) doesn't run software", was it a buildup to convince us that "GNU(glibc)/Linux" is really bad at running old binaries? Because your argument doesn't hold for the Linux kernel itself running statically linked binaries.


Only if those binaries were designed to be called from the Linux kernel directly, using only syscalls.

Last time I checked, hardly anyone uses their computer as an embedded board.


What am I chatgpt? Just make your point and tell us which 2000 binaries don't run and we can argue about whether or not that counts as a mark against backwards compatibility.

Also, is this a trick question about binaries that weren't patched for y2k or something?


The most stable API/ABI for the Linux desktop is provided by Wine.


Thankfully the year of the desktop is around the corner, by combining WSL with the original Win32.

Day zero feature availability, without compatibility issues.


This is impressive, but other parts of Windows are so dreary. Installs of apps that throw up all over the disk, Windows Updates that mysteriously fail in unrecoverable ways 87% of the way through and cryptic error codes and procedures to dig yourself out of the jam (before you must reinstall).


> Installs of apps that throw up all over the disk

This seems like a norm for most operating systems. Linux mixes files from all sorts of apps all over the place, for example, and a `make install` might put files anywhere.


> Windows has gone to extreme lengths to not only maintain API compatibility, but ABI compatibility as well.

Linux has a stable ABI as well. For a given architecture, like x86_64, syscall numbers and their arguments and their arguments/outputs are expected to be stable.

The stable API/ABI promise of Linux is the syscalls, because at the end of the day that is the interface between userspace applications and the kernel, and kernel devs take not breaking userspace very seriously.

And on Windows, the opposite is true. The stable interface is the Windows DLLs that you are supposed to use dynamically. If you hardcoded the syscalls, you cannot complain if your application breaks because windows only promises that the DLL will not break backwards compatibility, and they reserve the right to change the syscalls with any update.

So you can have a Linux binary that works across many Linux versions without breaking. You can also have a Windows binary that works on one version of Windows but not the next.


I have unfortunately run into exceptions. I tried to play Neverhood on my Windows install, and it wouldn't start up. Tried the various compatibility modes. No luck. I ended up running it under Wine in Win95 mode (or similar; I don't remember the exact version) on my Fedora desktop and it ran fine.

I haven't tried running too many old programs, though, so I have no sense for how common this might be.


"The car works great technically, people just have trivial complaints about the steering wheel being made of razor blades." That is becoming less and less of an exaggeration as Windows is progressively further enshittified.

NT seems to be a nice OS at the core, but that's more about what it can do and how it is implemented than about how pleasant it is to use. Some of its syscalls are much more convoluted than the UNIX ones. Typical functions take many parameters, some of them complicated on their own, and typical invocations pass a bunch of NULL arguments (you still need to roughly understand what they mean).


It’s close to common sense, end users don’t care which monkey(s) threw in the wrench if they encounter an error, just that some entity did.

The only caveats I can think of are that it must prominently display that it’s running in a “compatibility mode” and that any encrypted subsystems can’t revert to a lower standard of encryption, which may render the application unusable anyways depending on how tightly integrated it is.


It's hard to overstate*


Fixed


> all the other lame-ass things Office '97 does to take over your desktop all still work

I'm curious about this. What do you mean? I remember using Office '97 on a Windows '98 machine, but I don't remember Office trying to take over all my desktop.


> Microsoft learned that it doesn't matter why the BSOD occurred, just that bad software/hardware was giving them the bad reputation.

But the primary resolution to that problem was to force hardware vendors to write higher quality drivers (or for MS to write good enough default drivers that HW vendors wouldn't need their own), not to hide the BSOD. Technical details were only removed from them 2 decades after MS started fixing drivers.


Certifications have done a lot, but Windows now supports things like automatically restarting the graphics driver after it crashes instead of bringing down the system. I don't have inside information but from the outside, the HAL on Windows has evolved from freezing on a misbehaving USB device to just prompting you when you have exceeded the max number of USB devices supported. Anyone who remembers trying to dock a laptop back in the Windows 98 days remembers it being a dice roll if you would freeze the laptop or not.


The point of the article, in large part, is that when you’re designing an alternative runtime for a new platform, it is up to you what conditions are considered to be errors. Deciding to make a component of the runtime “inert” exists before and above the decision to make the implementation panic.

In this specific case: it is up to Microsoft to decide what the semantics of “printing on an Xbox” are. It could be an error; or it could be something that “could be supported in theory in the future, but for now has no way to actually accomplish it.” This is a design choice, not a development choice.

After all, in theory, you could print on an Xbox — plug in a USB printer, find a “game” that knows how to print (some enhanced port of a Gameboy game that had GB Printer support, maybe?), and tell it to do so. It’s not necessarily, fundamentally an error that a Xbox game is trying to print. You could define it as an error — but that’s a choice like any other, with trade-offs (in this case, to application portability.) You could define it as asking for the user to choose from no options, as the Xbox actually does. You could have the API lie and say it printed something. You could even actually support printing. These are all choices.

It’s only once you’ve made that choice, defining the semantics of “printing on an Xbox” as an error, that it becomes an implementation/debugging problem if that error isn’t thrown — i.e. gets “swallowed.”


UWP apps that don’t require specifically desktop APIs will run on Xbox — including, for instance, Excel.


> In this specific case: it is up to Microsoft to decide what the semantics of “printing on an Xbox” are. It could be an error; or it could be something that “could be supported in theory in the future, but for now has no way to actually accomplish it.” This is a design choice, not a development choice.

Anything wrong with "print to file"? There'd be no dead tree output but (file) output nonetheless & printing as a function should work.

Btw love the title of this article!


> I've learned this as "swallowing errors" and IMO it's a poor practice

This is not swallowing errors. This, in the Linux parlance, is not breaking user-space.

There are two ways to handle the situation presented: error out because the machine can never have printers or return an empty list of printers because the machine can never have printers. They're both valid but only one of them doesn't break user-space.


>It serves as a great vehicle to blare loud sirens at testing time that you (the programmer) screwed up (and that's ok, we all do), and it's time to figure out where and how to fix it :)

Right, but if you read the article, the author is talking less about the developer experience and more about the user experience. "blare loud sirens" is great if you're a tester/developer, not so much if you're an end user. When it comes to the end user, "swallowing errors" is preferable to crashing.


If you read the article, this isn't swallowing errors, it's just returning more-backwards-compatible errors.

> ...when the app tries to print, it will ask the user to select a printer, and show an empty list. The user realizes, “Oh, there are no printers,” and cancels the printing request.

> To deal with apps that get fancy and say “Oh, you have no printers installed, let me help you install one,” the function for installing a printer can return immediately with a result code that means “The user cancelled the operation.”

> a documented return value is ERROR_CANCELLED to mean that the user cancelled the creation of the widget. Therefore, apps are already dealing with the possibility of widgets not being created due to conditions outside their control, so we can take advantage of that

I'm annoyed when "modern web apps" (or similar desktop apps) seemingly do nothing when there's some error, you don't know if you need to wait a bit, or click again (great fun when the UI jumps 1ms before your re-click), or full reload/restart ... luckily that's not at all what this article recommends!


I’m sorry, maybe the article used the wrong example but the main issue comes from the fact that an Xbox app is trying to print something. It should fail, not for the developer experience, but because to start, there is no way the user would want to print something on an Xbox. Something is already really wrong with your app if it tries to do things like this.

Also he says that apps are developed and tested on PCs and that they could print in this context. I don’t know a single thing about Xbox development but I hope you can run/debug them in the Xbox environment (or a simulation).

Let me hope that nobody is running their Xbox apps/games on Windows APIs at development time and releases them on Xbox without further testing.


The point is that the UWP allows running apps developed and tested on PCs on an Xbox. It's for the user's convenience (not having to wait on developers to port to Xbox) as much as the developer's (not having to port to Xbox).

If a user wants to run an app on their Xbox, telling them "no, the developer didn't test this on the Xbox, so I'm not going to let you do that because you might try to print and get confused about it" isn't what the user wants to hear.

When the app tries to print because the developer was "lazy" and didn't test on Xbox, telling them "I'm going to crash your app now because you clicked Print, even though I know you're on an Xbox and I could just ignore that" also isn't helpful to the user.


> The point is that the UWP allows running apps developed and tested on PCs on an Xbox. It's for the user's convenience (not having to wait on developers to port to Xbox) as much as the developer's (not having to port to Xbox).

It's interesting because that's true in some way (in the sense that PC and Xbox are different), and also not true in another (in the sense that a Xbox is in a way a PC, only with a different UI paradigm)

So in the latter sense UWP allows developing apps for that universal platform, and it only so happens that some apps are only designed, developed, and tested for one system (PC) these apps can run on.

In a way I can see working from the Xbox up being a better way to have a robust, secure, uniform platform than the Windows 8 attempt of slapping a secondary paradigm on top of the Windows 1.0 / OS/2 descendants.

I mean, the facility that underpins e.g WSL2 is exactly the same as the one that underpins Xbox game/apps segregation and Quick Resume. In a way the Xbox OS is very much like Qubes OS! In a way the OS UI we see on an Xbox device is a UI for the hypervisor itself.

I would certainly be interested in a "PC" that is so stable, restores state exactly upon updates, "it just works", allows to play games, allows to run a bunch of Linux VMs, with forever perfect backwards compatibility across hardware arch changes and OS evolution through virtualisation/emulation, and has a UI that allows many kinds of inputs and scales from big screen (gamepad, that accessibility input device I can't recall the name) to desktop (kb+mouse) and possibly laptop or even tablet/phone.

I mean it's not that far fetched (technically) that MS would announce tomorrow that an Xbox can run Linux, Windows 10, or even Windows 3.1 in a VM: all the facilities are there and you can even plug a keyboard + mouse today.

One may philosophically balk at the idea ("How dare you touch at my very open IBM PC! Where are my floating windows! Freedoooom!"), but I think it makes sense technically, and it makes sense as a product, and MS has all the bricks to make it happen.


> Something is already really wrong with your app if it tries to do things like this.

The base philosophy of "if it's wrong it should fail" is primarily for developpers, and shouldn't apply to generic customer products.

If it's dangerous, or will cost money, or will have severe ill adverse effects, I'd see the point. If a credit card transaction is wrong, make it fail.

But short of these extremes, the default should be graceful handling of exceptions and help the customer app keep going and deliver some value to the user even if it's poorly written, mishandling the context.


Part of the context here is that UWP (universal windows platform), is a target to write-once and run on any windows platform situation.

This made much more sense when Microsoft had multiple platforms running windows with just different sets of apis activated.

At it's peak, this was: PC, phone, hololens, Xbox.

SMS apis may only work on phone, spatial APIs may only work on hololens, printing may work on several, but not all targets. There are ways for developers to check which APIs are supported at runtime, but you can still call these APIs since they are part of the UWP surface.


Maybe then raise an assertion error, which only has an effect in development mode.


Nothing is being compiled here; your customers aren't running debug builds of their apps, and the API code is part of the platform and isn't running the debug bits.


Even as an end user, I hate when my computer seems to be trying to hide something from me. Even if I can't do anything about it, I want to know it's happening. Don't worry, Microsoft. I'm a grown-up and can handle the bad news. If I'm a layman, maybe I just dismiss the dialog and try again. But if I'm a little more of a power user, maybe I'll look up the error message and see if I can start diagnosing or helping.

If you swallow the error message, I'll have zero idea that something is even going wrong! And almost just as bad: if you put up one of those useless infantilizing "oopsie doopsie computer made a poopsie" error messages, I still won't know what went wrong AND I'm being treated like a moron.

I worked for a software company once where our software basically crashed every 2-3 hours of continuous use due to a huge backlog of technical debt, memory leaks, and years of rushing. My manager's solution to this was not to fix the bugs--it was to build a separate "launcher" process that would detect that the application crashed, eat the error messages, and silently re-launch it hoping the user doesn't notice. Way to treat your users with respect...


There is no error message here - more often than not it's a straight up crash. No HRESULT, no popup, just NullPointerException, straight to jail.

In many cases like this, crashes like this are in app startup, so it's not like you learn not to hit a certain button - it's just that the app doesn't work, an awful UX.

As called out in the article, there are (and always should be) APIs like "IsPrintingEnabled" so that forward-thinking apps can show better UX. These practices aren't for those apps, they're for everyone else.

Also, if your app preserves state well enough that a keep-alive daemon can restore after a crash and the user doesn't notice, that is ABSOLUTELY an improvement in UX over just crashing. Sure, you should still fix the bugs, but don't let perfect be the enemy of good.


That is a dangerous assumption. Unless you know a great deal about every possible use case, you can't know the potential ramifications of incorrect output. Proceeding from invalid state (which would often be the result of swallowing errors) is essentially undefined behavior.


This isn't invalid state. They're not telling the app about a fake corrupt printer, they are using the API contact to represent the truth (there is no printer you can use) in a way the app already has to support


But I was responding to a general statement.


And I still think you're wrong. If incorrect input can't be handled gracefully in a way that you can be sure nothing bad will happen, it's possible that crashing is the best option.

But I think in most cases that just isn't what's going on. An unsupported API that makes a feature not work is just not a big deal. Lack of support, say, for a cryptographic primitive, could be a big deal, so you might choose to handle that case differently.


And would you treat an API endpoint that's down the same way? Just silently ignore that a feature that's part of the user's workflow isn't actually working, that maybe only half of what was supposed to happen when they pressed a button actually happened?


Yes, and in the case presented in the article -- trying to print on an Xbox -- we really do actually know the potential ramifications of trying to print and then being presented with no printers to print to. Simply: there are no ramifications worth worrying about.

On the other hand, we do know what will probably happen if an undocumented exception gets thrown: the app will crash, possibly causing the user to lose data.


It has irked me for decades that when the internet connection fails, all you get is a message that it failed. But what failed?

1. the software on your computer

2. the computer's hardware

3. the ethernet cable or wifi

4. the switch

5. the router

6. the cable modem

7. the internet cable to your house

8. the ISP

9. the remote system you're trying to connect to

Nothing has improved for decades.


This is something I kind of like about the Microsoft APIs. Their error codes aren't always perfect, but at least they give you some indication where things went wrong.

From MSDN:

> An HRESULT value consists of the following fields:

> A 1-bit code indicating severity, where zero represents success and 1 represents failure.

> A 4-bit reserved value.

> An 11-bit code indicating responsibility for the error or warning, also known as a facility code.

> A 16-bit code describing the error or warning.

The "reserved value" also includes a bit for non-Microsoft code (which driver vendors and other API producers can use, although I don't know how often they do)

There's a list of common "facilities" here: https://learn.microsoft.com/en-us/openspecs/windows_protocol...

As a regular user, you will see errors like 0x8ACEF00D, but if you decode them, you can get a sense of what part of the system ran into the failure. Compared to the "negative value indicates failure, look up the possible failures and what they mean for every function" approach many other APIs follow, that's a welcome change.

Of course there's no guarantee that Microsoft doesn't return some kind of meaningless internal E_SOMETHING_WENT_WRONG value, but for a lot of APIs, there are details hidden in plain sight. It won't tell you your ISP's fiber has snapped, but it'll tell you if the problem is within the driver, a security limitation, an HTTP error, or a generic network stack issue.


HRESULTs are well intentioned. They originated in OS/2; but Microsoft always seemed to use them half-heartedly.

Users should not be seeing "08CAE5D012" error messages. They should be seeing "Connection refused. (08CAE5D012)" messages, or "No connection. (83255321)" messages instead.

There's is a non-trivial protocol for translating HRESULTs into error text; but it is often not supported properly by Windows applications, or Windows OS components.

e.g. DirectX which returns generic 0x8004005 E_FAIL errors. Or the WinSock APIs, which return HRESULTs, but don't provide text message translations; or Microsoft Installers that report raw HRESULTs with no attempt to capture the associated error text.

With discipline, the entire system could have worked. But there wasn't, and it didn't.


You're making the assumption that it is all caused by hardware or software malfunction in the sending of an IP packet to the target server. However the first step is usually a DNS lookup. A list would look more like this:

1. DNS lookup fails because the DNS server address configured at the computer OR router is incorrect 2. DNS lookup fails because the configured DNS server is down 3. DNS lookup fails because some firewall is blocking requests to it 4. DNS lookup fails because the network was congested 5. DNS lookup fails because of interference in the Wifi channel from other Wifi networks 6. Etc. Etc.

So indeed, usually when the network is down you only get "DNS lookup failed". Because the actual reason may be complicated. Of course, usually it is due to your computer not being connected to a router so usually the error message hints at that (in layperson's terms: not connected to the internet). So that's why browsers hint at it being your connection, i.e. ethernet or wifi.

But there is no way to make sure. All we know is that DNS seems to fail. The reason it fails could be any part of its configuration which is spread out across physical systems and software components.

The best we can say: probably your ethernet/wifi connection. If we trust that none of the other components are failing then it must be your connection that is failing.

It's like trying to find out what's wrong in 1+2+32+4=10. Sure, it seems like the 32 should be a 3. But maybe the 10 should be a 39. There is no way to tell anymore. All we can do is make an educated guess.


Add a parallel step there, somewhere, for DNS. My raspberry pi runs pihole but the hardware is failing somehow so the server crashes so DNS lookups fail. All existing connections are fine, direct IPs are fine, locally cached results are fine, but new lookups fail. It is somewhat fun to watch it happen.


Windows has a tool to diagnose network problems, and it's usually completely useless but I think DNS not working is something it does identify.


Windows has a button to diagnose failed internet connections, but it has never reported anything other that the internet connection doesn't work. It's pathetic.


Keep going... ...

Try: ISP router intercepts DNS and drops the record because your company put private addresses on public DNS and the router has rebind protection.


It's similar to when you try to print something, and nothing happens.

1. is the printer turned on?

2. is the printer out of paper or ink?

3. does the cable have a loose connection?

4. is it the wrong printer driver?

5. do you need to reboot windows?

6. do you need to power cycle the printer?

No help anywhere. You just try things one by one, sacrifice a small animal, and then maybe the printer gods will smile on you and the printer will print.


I've been suffering that TODAY.

"Connection Refused No Further Information"

Well thanks pal.


I was getting the equivalent from my Roku box the other day, something like "no connection to the internet". Sigh.


As a Go programmer, how often do you check if fmt.Print returned an error? You get to assume that stdout and stderr exist for a start, even if your code is being run in an environment where that makes no sense. And what is the correct behavior for your software when IO errors start happening when you print? In a dev environment, probably crash. But in a production environment? A customers workstation?

The article isn't so much about swallowing exceptions, but more about designing the system so you don't have to raise exceptions.


> Not only does it not solve the issue at hand

It does actually. This approach ensures that old apps (whose authors never thought it would run on something called an Xbox) will seamlessly run and perform all functions properly except for printing, which isn't supported on Xbox. Panicking here would mean every older app has to update their code to support Xbox.


Agreed this is akin to

  HTTP 200
  {"error": "Not found"}


Not at all! It's like porting a program which expects there to be a TCP stack to a system which doesn't have one, and wiring up a component which responds to all HTTP requests with 404 instead of letting it hang on an infinite loop or crash. Say it uses a browser for rendering, but in the original you can also fetch websites, and the assumption is deeply baked into the code.

If your choice is between playing whack-a-mole with all parts of the system which might call out, or just issuing a 404 (after all, if there's no Internet, you're not going to find a web page on it), that's a reasonable way to solve the problem.


> responds to all HTTP requests with 404 instead of letting it hang on an infinite loop or crash

How is a 404 equivalent to not throwing an error? 404 would be like throwing the error and then not handling the 404.

And the equivalent of hanging and crashing in the xbox example would be hanging and crashing.


Nah I don't think this counts as swallowing errors.

There's nothing wrong or buggy about the printing API on Xbox returning a list of no printers instead of an exception.

It's essentially the Null Object design pattern. Even Go implements this in the way that a zero list can still be accessed an jsut behaves as an empty list.

Or in unix how /dev/null exists, which implements the file API but doesn't do anything. This is way nicer than fixing every UNIX program to handle stdout not existing sometimes.


Think of it like an emulator. The goal of DosBox is to provide Doom with the environment it wants so that it will run. That will necessitate some amount of lying.


This is something that Elixir nailed. The typical idioms for return types are `{:ok, ok_value} | {:error, error_value}`, for which callers can pattern match against and handle appropriately. If fail-fast is desired, many functions will also have a variant signaled by a postfix exclamation mark (e.g., some_function!(...)), that returns `ok_value` or raises an exception.


> This is something that Elixir nailed. The typical idioms for return types are `{:ok, ok_value} | {:error, error_value}`, for which callers can pattern match against and handle appropriately.

Agree this is a good pattern. Im not categorically against throwing errors but I like returning errors or the result and then having to check at the caller. Do this in typescript a lot.


Any typed language could use this pattern, though with Elixir specifically it was idiomized from the very beginning and all libraries use it, which makes error handling very consistent even when piping operations. The common option to fail fast is also handy when crashing the process is preferred and no matching is required to unwrap the value


> The idea here is to have the printing functions all behave in a manner perfectly consistent with printing being fully supported, yet mysteriously there is never a printer to print to.

That kind of thing intuitively sounds bad. But I guess of this is in a space shuttle I would take that back.


I wonder if Go's panic was inspired by Symbian OS User::Panic, an uncatchable sort of exception that was only used in situations when the programmer screwed up. It would kill the entire thread.

Not limited to testing time, though.


Completely disagree. Getting back at the programmer for making a mistake isn't what matters. Presenting the best experience possible to your users is all that matters.

If the user clicks on a print button in an app on the Xbox, and the app crashes (possibly losing some of the user's data), that's a bad experience for the user. Why do that to them just to stick it to the programmer?

And on top of that, now some developer at some company (often not even the person who initially made the bad assumptions about printing) has now been called in on a weekend by their boss to scramble to fix the issue and push out a new release. Why do that to people?

Regardless, also consider the API contract. If the printing API isn't documented to throw any exceptions, and you start doing that, you're breaking the contract. You can't blame the programmer for not considering platforms without printing support; you've documented that API as always returning something without blowing up.

But that's still irrelevant; don't break user code just because you can, or because it's more expedient for you to do so.

Your Go example is completely unrelated; you're talking about making things blow up at testing time, which I agree is the right thing to do. But that's also when you have full control over the code and the testing. If a third-party platform API starts behaving in ways you didn't expect it to behave, that's a whole other thing.


>You're mostly not supposed to use it or recover from it at run time

Are you serious? I thought a key principle of Go was to handle panics in a layered way at runtime


in my experience that's partly true (it's a judgement call and lies on a spectrum). Like a HTTP server should handle panics in handler code so as to not crash the other go routines handling requests. Or maybe a long running queue worker (eg reading off SQS) should recover from a single go routine handling a message (assuming it can recover and handle the next message successfully).

But it'd be way out of scope to put a recover block outside every function call just incase it did a runtime error: index out of range [1] with length . In this way its much different than try catch in languages that explicitly call out what they throw


This is the Microsoft way to do things, this is why their products like Windows are so crappy, full of bugs, unexpected behaviors and a big dump of shit of legacy behaviors expected on top of a lot other legacy behaviors on top of another 1989 legacy behavior that every forgot.


Much of the crappy legacy behavior that Microsoft maintains is the fault of other applications, not themselves.

The classic one is the error code for the file open function. Early DOS would return error codes of only 3, 4, 5, and no more. DOS programs would actually just indirect-jump using the error number as an index into a lookup table of addresses. When Microsoft tried to add any error codes (say 6), the program would jump out into hyperspace since 6 was beyond that lookup table and that memory word could be anything. So Microsoft was stuck folding every possible file open error into code 5, and to this day that's why just about any file error in Windows just says "5 Access Denied". And no, Microsoft couldn't add more error codes and just let the applications break, since then nobody would buy the new operating system versions that their programs wouldn't work on.


No, it's not. Like what is described in the original post, it is they spirit. For example for the case with the printer and the xbox, they could have an explicit obvious error for the application. Then it is the task of the application dev to validate its application for target it will run on. If it is does not work, it does not work. Otherwise, you will still have dozens of bugs and unexpected behaviors, so a crappy application.

And new app developers will have to build upon that. Imagine the next app developer, you have to take into account that a platform pretends to support printers when it is not the case. So you will do things like: if there is a printer api but i don't see a printer available (/connected), pretend that we can't print and don't show the button... and so on...

If you have doubts about that, you can read the history of the openxml format: https://ooxmlisdefectivebydesign.blogspot.com/2007/08/micros...


> they could have an explicit obvious error for the application.

No, they can't. "The application" has already been written by a 3rd party who could be out of business for all we know.

> If it is does not work, it does not work.

Or you could let it keep working. Somebody might depend on it, and none of this is their fault.


> When Microsoft tried to add any error codes (say 6), the program would jump out into hyperspace since 6 was beyond that lookup table and that memory word could be anything. So Microsoft was stuck folding every possible file open error into code 5, and to this day that's why just about any file error in Windows just says "5 Access Denied". And no, Microsoft couldn't add more error codes and just let the applications break, since then nobody would buy the new operating system versions that their programs wouldn't work on.

This doesn't pass the sniff test because

1. There's documented error codes that go all the way up to 16k: https://learn.microsoft.com/en-us/windows/win32/debug/system...

2. There's file related error codes way above 5, eg. ERROR_FILE_EXISTS 80 (0x50)

The general gist of your comment is correct though. Suppose windows didn't have file locks before and they were adding it. Returning an error code like FILE_LOCKED or whatever would be much more descriptive, but would also require all existing code to handle this error case. With that in mind returning ACCESS_DENIED makes perfect sense, even if programs aren't using jump tables.


> Much of the crappy legacy behavior that Microsoft maintains is the fault of other applications, not themselves.

Well. I have two or three (I am not even sure because for one email address there are probably two accounts, but no way to distinguish between them) MS Teams accounts. There is no painless way to switch between them. Currently there are probably at least three different MS Teams apps installed on my machine, one of them self-installed without my consent (my PC is not managed by an org or domain, it's mine). Switching accounts involves several confusing errors, at least three password inputs, and several complaints by MS Teams that something is wrong, but it won't tell me how to fix it.

Use the browser version they said. Well for scheduled meetings it works, but for adhoc calls Firefox does not (there is no reason provided, but at least it does say outright), while Chrome seems to work but does not transmit my voice and camera. All other meeting software, of course, works.

I am not the youngest anymore and this is my lifelong experience with Microsoft. Its software works barely enough to sell to corporations; poor users have to endure it.


People are reacting negatively as expected, but stuff like this is exactly why you can click on a file that was written in Word '97 or a game that was compiled for MS-DOS three decades ago and it opens on your computer exactly as expected. Backwards compatibility is always messy. You either do it imperfectly or don't do it at all.


I hear that refrain often regarding Microsoft, but with games, I have not had good luck. I resort to using GOG, which itself ends up virtualizing the environment anyway. For example, I do not think anyone would have success installing the original Sim City on Windows 11.


Fallout 3 was unplayable (without mods/patches) on Windows 10 for many years because of its dependency on "Games for Windows Live" from Windows 7


Yeah, people frequently trot out the Sim City classic example, but the fact is that games in particular have borne the brunt of Windows API changes. If it didn't happen we'd have no need for wrappers like dgVoodoo: software once only meant to wrap Glide calls, but now used to get around deprecation to DirectX as well. Not to mention the breaking changes to the audio stack that happened between 9x and Vista.


A file that was written in Word '97 did not even open exactly as expected on two different computers 25 years ago. Formatting depended on the installed printer drivers. Good luck with that document today.

My LaTeX files from 35 years ago, on the other hand - they just do fine.


>My LaTeX files from 35 years ago, on the other hand - they just do fine.

Yeah, because they're plain text. A fairer comparison would be whether they render pixel perfectly as 35 years ago, which I doubt.


If you compile them to DVI you'll get the same DVI file.

Compiled to PDF you might get very slight differences.


If you're rendering to DVI, it's explicitly defined as a bug if it doesn't compile to exactly the same pixel-perfect output as a previous version.


>the same DVI file.

Which is used by approximately no one. Good luck uploading your resume in DVI.


Good luck uploading your CV in PDF. I tried that a few times and got moaned at a load that my CV must be in Word format. In the end I converted the PDF into images, and created a Word document in OpenOffice (this was a while ago) with one page image per page. Got moaned at for that too.


Heh. A buddy of mine once applied for a Linux job and sent his resume as a PDF. They called him back: "OMG, you're the only applicant who didn't send a Word file. We're not worthy."


Did he create the PDF in LaTeX?


The only reason they want your resume at all is to run a keyword extractor over it. If you know this, why are you making their job harder?


I haven't had that experience for a single job that I ever applied to. Always sent in PDFs without any issues.


Recruiters and large firms tend to ask for a Word file. I sent the plaintext file (minimal markdown) I used to generate the pdf to a recruiter recently. They directly asked for a docx instead.


Recruiters probably edit the file before passing it on to the actual business... Add some more buzzwords, remove direct contact information, obscure exact project details. Some recruiters play quite dirty business and likewise assume the worst of their customers.


That is exactly the complaint I got about my word-document-with-page-images. The recruiter couldn't work out how to edit it. I saw the CV they actually ended up sending to one of the workplaces I interviewed at. They had retyped it, and it looked awful.


> Recruiters and large firms tend to ask for a Word file.

Again, not my experience at all.

I think if a company didn't accept my PDF CV and asked for a Word file instead, I'd strongly reconsider whether I'm actually interested in working there.


They're not plain text, they're a text encoded structured file format. And the file format is stable.

A stable file format is the most important difference here, but the text encoding means that small incompatibilities can be solved by a human rather than needing to rely on an upstream maintainer to recognize and explicitly handle your unique situation.


If I recall correctly, the common phenomenon where you open a Word document, immediately close it, and are asked whether you want to save your changes (???) has something to do with printer settings.


A file from 1997? Maybe if you get lucky, but there's also a good chance that it will simply look wrong in any office application you try. With Word you can't even guarantee that reopening the file on the same computer & version won't change its formatting. That was the reason I learned TeX.

And games? Microsoft broke numerous games by shutting down GFWL. I had to pirate Dark Souls as my original copy wasn't playable until it got re-released on Steam.


>With Word you can't even guarantee that reopening the file on the same computer & version won't change its formatting.

Source? This seems utterly bizarre.


Before the new '.docx`, '.xslx', etc. formats, when it was still just .doc, .xsl, etc., the document format was (as I've heard it told) essentially just a memory dump of Word/Excel's state for that document at the time you saved. And since it's easy to imagine that serializing/deserializing such a complex thing might not be always 100% perfectly idempotent, it would indeed happen that just the act of opening a file would change it in some subtle way.

That hasn't been the case in a long time, though.


Worse than subtle formatting changes was some kind of corruption that could slowly swallow bits of your document without you noticing. Sometimes going back before the corruption had visible effects was not good enough to stop it from manifesting again.

I remember back in school religiously saving new versions of Word documents so that if the newest version went bad I could start a fresh doc, then copy and paste sections from old versions via Notepad to cleanse the corruption. (Direct Word-to-Word could bring it across — I guess that tells us something about how they implemented copy+paste between documents, too!)


You're right, Office documents were essentialy a memory dump, but only for Office <= 95 if I recall correctly.

Starting from Office 97, they switched to an improved .doc, .xsl, etc. file format (even though it was still binary).

That's why modern software such as Office itself or LibreOffice call the .doc format "Microsoft Word 97/2003"


They were reportedly written as memory dumps for speed.

https://www.joelonsoftware.com/2008/02/19/why-are-the-micros...


the new formats are actually zip archives believe it or not


They are ZIP archives... of XML. That's what the 'x' stands for in '.docx', '.xlsx', '.pptx', etc; it is Office Open XML[1].

[1]: https://en.wikipedia.org/wiki/Office_Open_XML#:~:text=Office....


Difficult to prove considering that was a decade ago, but it did happen to me. Randomly changed font in a random paragraph, randomly repositioned images, etc. Maybe I accidentally broke the document in some way, I don't know, but Word certainly failed to restore it to the exact state it was saved in, and it was always on the same PC and software.


I don't know if anything's changed but for a long time a lot of Word's formatting was impacted by the printer you had installed and/or selected. So it was pretty easy to run into scenarios on a network where printers being taken offline/their capabilities changed resulted in documents getting reformatted.


I had the same with OpenOffice (before LibreOffice was a thing). I created a nice document while logged in remotely to a Linux computer over Xvnc. When I opened it on the native terminal, the layout was different. Same computer, same version of OpenOffice, different X server.


MS-DOS software doesn't work on modern 64-bit windows

you get a dialog saying "unsupported"

now you can download dosbox but that isn't really "exactly as expected"


I wish this was actually truthful. I’ve had a gigantic headache getting every childhood game I kept working. In almost every case I gave up or re-bought from GOG, basically paying for the work done to sort out compatibility.


I think the reason this is getting a negative reaction is because he doesn't really clearly state the problem he's actually trying to solve until the end (and describes it as "bonus chatter" when it's actually just a much better explanation than he gives at the top of the article).

> To clear up some confusion: The idea here is that the printing API has always existed on desktop, where printing is supported, and the “get me the list of printers” function is documented not to throw an exception. If you want to port the printing API to Xbox, how do you do it in a way that allows existing desktop apps to continue to run on Xbox? The inert behavior is completely truthful: There are no printers on an Xbox. Nobody expects the answer to the question, “How many printers are there?” to be “How dare you ask me such a thing!”

If he just used the words "existing desktop apps" in the second paragraph of the article instead of the second to last, I don't think people would be reacting so negatively. Instead, when he talks about avoiding "gaslighting" by returning an invalid pointer by just gaslighting in a different way by lying about the error that occurred, it almost sounds unhinged.


Umm but you can’t find a current version of Word that actually does that. Try it sometime.


Here's a rather large (5MB) vintage 1996 Microsoft Word document: https://archive.org/download/cd-pn-0527a/CD_ROM.ISO/APPENDIX...

That file opens and appears to render just fine for me in Word 2016.

This has been my experience w/ Office files in general. Old files open and render very well in newer versions.


The point made above was "opens exactly as expected". So, does it look like the authors intended in 1996? I doubt it.


Just flipping thru it I'm not seeing obvious issues. In terms of being usable for reference I think it's reasonable. The diagrams and tables look intelligible and not garbled. Layout isn't visible screwed-up.

Will it be a 1-to-1 with printed output from 1996? Probably not.


“exactly as expected” is a much higher bar to clear then roughly as expected.


If you "doubt" it, please provide a specific example of what you believe is inaccurate in the document rendering.


As it happens, we just had this discussion regarding a Word document from 1990: https://news.ycombinator.com/item?id=39357709


Quote from the article:

"Converting this document from its original format was a bit of a victory for open source software. And a lesson in how hard document preservation is."

So, opening this document was hard and that it finally worked was not because of Microsoft's alleged famous backwards compatibility- which is a myth in my book.


I doubt it because, as I said, Word did not even render the document the same on two different installations back in the day. Contrary to LaTeX, there is really no way to know what "opens on your computer exactly as expected" even means. We do not know what the original author intended it to look like, because we do not know how the document looked like to them.

As long as there is no retroactive interpretation, like it happened with RGB, for example, the "doubt it" will stand.


Was able to do it just fine with these government files[0,1] I found on Google. Word version 16.82 on Mac (Apple Silicon too).

0: https://www.legis.state.pa.us/cfdocs/Legis/LI/uconsCheck.cfm....

1: https://archive.ada.gov/briefs/andersbr.doc


The point made above was "opens exactly as expected". So, does it look like the authors intended in 1996? I doubt it.


I assume the negative reactions are due to the large Apple user base on HN. Most of these people are likely so used to being told "this software was built for a version of your OS released 2 years ago so you can't use it anymore, tough shit", they've come to expect it.


You just created a scenario in your head that confirmed an existing bias in your head and then assumed that your made up scenario matched reality. Very weird to read.


nah, it's because all of this is just lip service. windows11 is getting worse and worse.

and cool that Mr Chen thinks about UX and compatibility, but MS as whole does not really. important business apps got special treatment, and that's it. (MS and its corporate entourage solved this mostly by providing Windows and "security" patches for it, for a lot of money.)


I find nothing quite as frustrating as UIs that suggest a device could exist, but it's not there right now. I then have to spend time to discover that these devices are not supported, and that screen was just some mock someone came up with.


Sure, but you'd be more frustrated if your app just crashed.

If the app is not prepared for printing not being supported, and printing just throws an exception, the app probably just crashes. That's bad.

If the app is prepared for printing not being supported, it should be calling the explicit API to check if printing is supported, and then not displaying the UI for printing if it isn't. The article is not about these apps, it's about what to do about apps that fail to check first.

The bug is with the app, but a good platform does its best to make bad apps work anyway, rather than have them just crash.


these aren't the only two options.

first of all, i certainly wouldn't be more frustrated if the app just crashed, but how about just letting the user know that the xbox can't print? why does everybody seem to think that's out of the question?


> but how about just letting the user know that the xbox can't print? why does everybody seem to think that's out of the question?

Because the situation described is about an application that was made for PC (which supports printing) and a user is trying to run it on an Xbox (which doesn't support printing) with the developer never even imagining someone will try to run the program on an Xbox in the first place. You can't implement a message about an error you don't even know will happen.


The Xbox system APIs can certainly notify the user directly. It's not like they don't have the ability to pop up system UIs.


The Xbox can (and probably can do that while simulating the "user pressed cancel" dialog API for adding printers) but my understanding for what yungporko wrote was that the program would be the thing that lets the user know the xbox can't print.


The original article is about how the Xbox implementation of the Windows printing subsystem should behave, from one of its designers. They considered making it throw an Exception, but decided to instead behave as if printing is supported but there are no printers, so that Windows apps would not crash.

My point was that, as an end user of such apps on Xbox, my preference would have been to have the Xbox OS tell me directly that printing is not supported on this system, even if the app doesn't know about this.


I do not have an Xbox to try but i do not see how these two are mutually exclusive. If you try to use an app to print you wont be able to do that because there are no printers. If you try to add a printer using the Windows API for adding printers (which AFAICT from the article is done via a GUI that Windows itself provides) then the Xbox OS could show an error message that Xbox does not have printer support and once you close it, have the API call the application made tell the application that the user cancelled the request (which is something, according to article, it already does - though i don't have an Xbox to tell if it displays an error message or silently returns the cancel code).

Xbox cannot tell you that there is no printer support before you try to do something related to printing because it doesn't know you may want that. An application that was made for Windows also can't do that because on Windows you can add printers (even fake ones that print to PDFs, no hardware needed).


An application asks the OS for the list of printers. The question is what should an OS with no support for printing do. The article says it should return an empty list. My point is that it should pop up a notification directly to the user telling them "hey, the app you're using is trying to access printing, but that's not supported on this machine" or some other language like this (it could then return an empty list).


Trying to enumerate printers doesn't imply that the application will use them, it could easily be part of the initialization of some framework, shared library, language runtime, or whatever. Unless there is some actual user interaction, there is no way for the OS to know what the user is trying to do. It is best to err on the side of not making assumptions.


> Sure, but you'd be more frustrated if your app just crashed.

I don't know about that. If it crashes, I might not try that thing again.


To me, a better solution would be for the system to pop up a notification informing the user that printing is not supported on this platform, and then whatever other solution is OK.


> To me, a better solution would be for the system to pop up a notification informing the user that printing is not supported on this platform

That's the whole point of this article - when you can't control the various platforms that your application is run on, you want to try to do the "least bad" thing, even if that platform didn't anticipate the situation of, in this case, telling people that printing isn't supported.


The article is the other way around -- it's written from the perspective of a platform developer trying to deal with apps that didn't anticipate the situation.


Thanks for the clarification, you're correct. The nuance/complexity is that the platform developer must conform to a platform spec (in this case, the Windows API) that usually makes some underlying assumptions about the capabilities of the system that runs it, which may not always be correct.


Yes, I'd add to that by pointing out that the "spec" is a de facto spec subject to Hyrum's Law, that is, people have built their apps against other implementations of the platform and inevitably don't handle any behavior not seen on those other implementations.


I waffle whether I agree with you. On the one hand, it makes sense to tell the user that clicking that juicy print button isn't going to work. On the other, it's a popup they'll have to dismiss telling them some recoverable error they cannot do anything to fix.


Yes exactly, but Microsoft isnt the one who can implement that.


This was about the Xbox printing subsystem, right? Of course they can implement that.


It would be whoever writes the software (ie the game) for the xbox.


The Xbox OS can very well pop up a system notification directly to the user if an unsupported API is being accessed. This is not Unix where you have to assume no UI may even exist - the Xbox OS knows full well how to draw its own dialog on the screen.


Perhaps the software author is to blame here then not Microsoft. Because they didnt handle the printer case. Where Microsoft comes in is that the software doesnt crash because the software provider didnt account for printers.


> With this behavior, when the app tries to print, it will ask the user to select a printer, and show an empty list.

I see Microsoft has not learned from 30 years: https://www.reddit.com/r/hacking/comments/djvzd/windows_nt_l...


That os amazing


The specific thing the author is suggesting is correct (components should suffer before users do), but I take great offense to their framing. "There may be times where you need to make an API do nothing." "The wrong thing to do is to have the printing functions throw a Not­Supported­Exception." No, no, absolutely no - what the author is describing is a hack to support a shitty client. Yes, you have to do this sometimes. No, it is not normal or generalizable advice.

The way they've worded this betrays the internalization of their suffering as a MS developer.


No, not a shitty client, just one that was written before you decided to make this change. If your API breaks it while it doesn't change, it's the API that's being shitty, not the client.


> No, not a shitty client, just one that was written before you decided to make this change.

Has the Xbox ever supported printing? Why even have these APIs? Just don’t offer them at all in the Xbox SDK. You shouldn’t be able to compile code that tries to call these when targeting Xbox.


It's an API that also targets Windows. Apps that use it can run on both platforms.


? Why even have these APIs?

Xbox essentially runs Windows. Therefore, the Windows API is available on Xbox.


But they are essentially removing parts of the Windows API, that’s what the entire article is about. Wouldn’t it make more sense AND be a lot less work to simply remove these APIs from the header files than to provide a stub implementation?


There are no header files involved. The whole point of this is to support running existing programs without recompiling them for the new platform.


What existing apps could you possibly want to run on a game console without at least a few modifications to make it suitable to run with the completely different control scheme and user expectations of a console.

It seems like an enormous amount of effort for an extreme edge case. It’s this weird obsession Microsoft has with the flawed idea that you should be able to run anything on every device without modifications. It’s their unwillingness to acknowledge that different types of devices require different user experiences.


It depends. Did the API document that it could raise an exception if printing isn't supported? Is that unhandled in the client? Then yes, it's a shitty client.

If you're talking about making backwards-incompatible breaking changes to an API, that's another thing.


In the context of the article, no, the existing API never threw (or was documented as capable of throwing) NotSupportedException.

The article:

> The app that the user installed on the Xbox was probably tested primarily, if not exclusively, on a PC, where printing is always available.

I.e. there is no concept in the (desktop) Windows printing subsystem of printing as a feature not being available; on desktop Windows, printing as a feature is available by definition.


I think this is the critical piece that should determine how you handle the error. If the API, as used by the client, when the client was programmed, was expected to potentially throw NotSupportedException or return an error code, then doing so sounds like the right way to go. Throwing/erroring is part of the API contract and the client should handle NotSupportedException.

If the API was never expected to throw NotSupportedException or return an error code, then all of a sudden starting to throw in a future release breaks the API contract, and the client cannot be expected to handle it sensibly.

EDIT: Duh! My comment is useless. This was the exact conclusion that the article came to, too. So instead of reading this comment chain, just finish the article :)


The mention of Not­Supported­Exception is a little confusing because that's a .NET thing, and the rest of the article is talking about Win32, which is a plain old C API where exceptions don't exist. I guess he's implicitly talking about a C# API built on top of Win32.

It's entirely correct to return error codes, and any client is expected to handle that.


Clients are not expected/required, however, to behave correctly in the face of unknown error codes that did not exist or have defined semantics at SDK-version-selection time.

Actual exceptions — in languages that have them — are a bit different, in that they “do” something by default: they propagate and unwind unless they’re caught. And so, new (unchecked, if in a language where that’s relevant) exceptions can be introduced after the fact under the presumption that the runtime’s default behavior for propagating unknown exceptions will kick in, and that this will trigger the desired result for applications that weren’t written in awareness of that particular exception.

Error codes aren’t like that; they have no default semantics as a class, only explicit default semantics per function and/or per algebraic error-code type, if-and-where documented as such. New error codes simply aren’t meant to be introduced in most APIs, unless those APIs have rules about e.g. generalized default handling for defined code ranges that new codes can be later slotted into.

Basically, error codes are weak enums. If you’re writing a dynamic-link library (or a runtime — same thing, basically), you’re not supposed to add new potential values to an enum used as a return value: client code will likely have been written to switch on the value with the known options as cases, and your new value won’t be in there.


> I guess he's implicitly talking about a C# API built on top of Win32.

Correct. The error `ERROR_CANCELLED` is defined in WinErr.h and it's translated via `HRESULT_FROM_WIN32` in the same[1]. It was this change pointed out in `CreateWidget` to get around returning the null pointer that he was suggesting would be better to make the API inert.

[1] - https://learn.microsoft.com/en-us/windows/win32/api/winerror...


If you are building a software platform which has been adopted by more than a handful of developers then you're going to have some shitty apps, in which case you have to do this stuff. Yes, it is completely normal and generalizable to all platforms that have wide adoption and take backwards compatibility at all seriously.

Raymond is behind arguably the foremost exemplar of this (Windows) but the same thing happens in the Linux kernel ABI, glibc, the web platform, Java, and so on.


The issue is that sometimes you need to implement an API which existing clients are already using. You can't go back in time and re-compile, much less re-write the clients.

It all depends on how the clients are currently using the API. If the clients are already testing for NotSupportedException, then that's what you should return. But if not, you need a different approach.


well, that seems like an important piece of the contextual puzzle, because the Xbox printing example by itself seems extremely dumb. (issuing/publishing games on Xbox is not a wild wild west of unknown binaries, if someone cannot get the source code for their thing they are very unlikely to get their thing on Xbox. yes, there are probably binary blobs, but still, to me in this context it's ridiculous that instead of a an exception handling wrapper on the application side the platform does these fakes.)


> No, no, absolutely no - what the author is describing is a hack to support a shitty client.

If you were on the Windows team and I was your manager, I might fire you for that.

This is Windows. You do not break applications that users depend on. Ever, ever, ever. If you have a "shitty" or misbehaving client application, you use whatever workarounds, shims, and compatibility hacks it takes to make the application work as expected. Even if it means having special memory management code for SimCity so it will work.


I really appreciate this approach. It actually takes, in my humble opinion, much more discipline (and requires checking ego at the door) to implement this idea, compared to the “my code just throws exceptions or a 400 Bad Request anytime you aren’t following the most recent revision of our API” mindset. I work on Web apps which are much closer to that second approach usually, but if I were working on a platform (NT) which was 30 years old and will live another 30 years in all likelihood, you 100% have to take the approaches Raymond Chen is explaining.

“We’ve decided software that operates your 100 ten-million-dollar-each CNC machines is ‘shitty,’ so buy new equipment so you can get Windows 11” isn’t going to fly, it would get the whole company laughed out of the room.

Especially because what is allegedly making them shitty would just be someone’s failure to predict some minor detail about the future of the platform. APIs do have to change, and the creative part is thinking of how they can be safely rendered inoperable without damaging anything that didn’t predict that removal. Sure, you can’t print, but that’s in this example a deliberate design decision of the platform, probably for good reasons.


> “We’ve decided software that operates your 100 ten-million-dollar-each CNC machines is ‘shitty,’ so buy new equipment so you can get Windows 11”

...and then you'll also have to re-write your software to support Win 11, of course.


I also took issue with the Xbox example, and I think it's a context issue. When I read it, I interpreted it as an API for new apps/games to use. In that case, they should be testing on an actual Xbox before shipping! And why would the app be trying to print in the first place if it's designed to run on an Xbox?

But I suspect the situation this is being designed for is existing PC apps being ported to an Xbox. OK, in that case I can see fudging the API since there might be obscure corners that the devs didn't think about that try to print. But I'd still say the devs should be testing on an Xbox and make an effort not to attempt to do things when it doesn't make sense for the platform.


Just to add further context; this isn't apps being ported to an Xbox, they notionally need no porting; the Xbox is a "Windows" system. The only actor in this scenario is the platform developer figuring out how an existing API should behave if called in a context the authors very much didn't expect (who expects their Windows app to be run on an Xbox?)


I guess I'm confused then. Is the expectation that you can just run any Windows app on an Xbox, unmodified? I would think you'd have to at least change the UI


Yes, that is a thing the Xbox supports (for UWP apps, not every Windows app ever). The UI is indeed often not great.


The "shitty client" was written long ago by a company that is out of business. YOUR customers rely on that client, and if it stops working because of a change you made they will blame you.


Broadly speaking I agree with you in principle - but in practice over time you come to realise that there are only shitty clients. They might not intend to be, they might not have started out that way, but time is a destructive thing...


> The way they've worded this betrays the internalization of their suffering as a MS developer.

While I feel less strongly about this Xbox/printing example, I remember Bill Gates saying "I reboot my computer every day" which is a similar mindset-- this culture has been forced to adopt a certain form of "hygiene" due to that same culture NOT adopting hygiene preemptively when they built their systems.


Everyone here is hung up on doing "nothing" and handling "errors" and I feel like the post does a poor job explaining how it is not just swallowing everything that's going wrong and going kumbaya. The actual context is that the author is doing emulation/compatibility for software that will not change, and that's very different from most contexts. This is especially confusing because Microsoft often blurs the line between the two themselves, and that's not actually what is being talked about here at all.

Really, emulation is all about telling lies. Your Xbox doesn't actually have a way to attach a printer. You're running a game on Linux, not Windows. Your fake iPhone is actually a ARM server in AWS. The point here is that if you're going to lie you better do so convincingly. That's because you need existing applications to still work! When Microsoft says you can port your existing Windows app to Xbox the promise for the Windows app was that it would be able to print, and so Xbox needs to lie for that to happen.

This is very different from a normal error. If a program does a use after free, and you silently pretend the bug doesn't exist by working around it, then you're not doing anything correctly. That's because nobody promises that your existing use after frees will be bug-for-bug compatible on a new platform.


> There may be times where you need to make an API do nothing. It’s important to have it do nothing in the correct way.

> For example, Windows has an extensive printing infrastructure. But that infrastructure does not exist on Xbox. What should happen if an app tries to print on an Xbox?

It says nowhere that the context is doing emulation for software that will not change. You just assume that because it supports the position you like. In fact, everything written applies to a program that I might write tomorrow for an XBox, and try to print something. There is nothing that designates this behavior only for old, unmaintained software.


If you write a program tomorrow, use the API correctly and this issue will not apply to you. This is for apps that aren't well written and don't check for the capabilities ahead of time.


Nothing Chen wrote motivates me to use the API correctly, that's the whole point. "Just don't do the bad thing" is naive. People will use APIs incorrectly, despite your admonition.


> "Just don't do the bad thing" is naive. People will use APIs incorrectly

That is the whole point! You don't have a choice for software that will not change - all you can do is try to keep it working anyway. Like they did here.

That you are not "motivated" to do things correctly is not a convincing argument otherwise.

If you don't want this behavior in your own apps, you don't have to invoke it. Using the API correctly sidesteps all of this but is not a choice when "doing emulation for software that will not change."


I generally advocate for things crashing early, for reference. I just happen to work on emulators and compatibility shims a lot, much like what Microsoft is offering here.


I love and hate this. On a visceral level I don't like dealing with issues via malicious compliance.

OTOH I absolutely agree this is a good call if your goal is for more users to be able to run more software on your platform, even if printing is broken.


What a weird thread of comments this was. There are clearly people who just don't like anything Microsoft does.

The point of the blog is to make the process of bringing apps (UWP) to XBOX be frictionless: no recompile required, no messy ifdefs, none of that extra work. The App would "just work". Then, it's up to the developers to start adjusting the app to fit the XBOX platform more. The important thing here is that the developer was able to bring the app with no effort to XBOX. This is good for both the platform and the developer.

To the user, it's a clear signal that they can't print since the list of printers are empty. But most importantly for them, the app did not crash or show the most hated error: "oops something went wrong. Try again later."

Is that message a better experience for the user? No.

Sure, the developers can recompile the app and add a more descriptive message but then we're back to square one.


I honestly feel like 95% of the people in this thread didn't understand the article.

for example, accusations of swallowing errors. That's not the point, not at all.


The point the critics of this piece seem to be missing is that there is not an exceptional case here that needs an error to be thrown. There are NO printers attached to the device (in this case by definition), and an app should cleanly handle that case, not crash. You wouldn’t throw an exception on a laptop just because it couldn’t reach the printer.


If you want a clear, modern example of a popular non-Microsoft product doing printer availability wrong, it's gnome-control-center.

Add a printer in Settings. While the printer is installing, click over to the "Color Profiles" tab. If you time it right, gnome-control-center will crash. If you dive into the details, you see that it was trying to enumerate the available printers (it knows one should be there) but that info doesn't exist yet. So it just crashes.

Thankfully, the fix is to just wait a few seconds for GNOME to finish installing the printer and restart Settings. Still, it's the principal app responsible for making your desktop work correctly as an end user with some unknown computing background. In a perfect world, this app should never crash.

It's hard to think about edge cases. It's even harder to imagine your handling of edge cases has its own edge cases. Right or wrong, at least the author is thinking deeper than "bad app, needs to be rewritten to support Wayland"


Once upon a time it was considered a great strategy for browsers to make the best effort to display a page, even if the html code had errors. Just try to guess the author's intention as well as you can, and go ahead. Errors are bad. Users don't want errors.

I thought we learned from that experience. Apparently not.


Browsers still follow that strategy. The effort to replace it with strict validation (XHTML) failed. What succeeded instead was HTML5, which went back and explicitly defined how every possible invalid sequence should be interpreted, so that browsers would at least be consistent about it.


Browsers being permissive with what they accept is what made the modern web possible.

If early browsers displayed an error the first time it came across an <img> tag, instead of just best-effort rendering the page, then every new browser feature would have been smothered in the cradle.


Go type in:

  <p>Hello
  <br></br>
  World!
And see the errors that now show up because of the wisdom we gained… wait, it still renders alright? I guess we still have much to learn then. Or, there might be something to gracefully handling certain classes of errors while crashing on exceptional cases.


Not sure if you meant to use <p> as an example because it's well-defined as an optional closing tag.

This is a completely normal usage and some people even author their HTML like this. Granted this is part of the effort to standardize error handling.

That unclosed <p> will auto-close as soon as you start another paragraph or close it's parent element. Likewise this is how I do lists these days:

  <ul>
    <li> One
    <li> Two
  </ul>
The subsequent li's will close the previous and the bounding ul ends the last list item.


the evolution we have seen in software in the last 20 years isn't great except for LLMs, but then again, they messed them up with censorship.

I would not miss much if I was time-traveled to 1999.


What did you think we learned?


That every single behavior that attempts to guess the users's intent becomes a relied upon part of the software, and this over time grows to an impossible amount of cruft.

See this, hilariously hosted also by microsoft: https://techcommunity.microsoft.com/t5/discussions/funny-sto...

> And then Google built Chrome, and Chrome used Webkit, and it was like Safari, and wanted pages built for Safari, and so pretended to be Safari. And thus Chrome used WebKit, and pretended to be Safari, and WebKit pretended to be KHTML, and KHTML pretended to be Gecko, and all browsers pretended to be Mozilla, and Chrome called itself Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13, and the user agent string was a complete mess, and near useless, and everyone pretended to be everyone else, and confusion abounded.


In 2024, so we still have websites that are served differently depending on the User Agent?

Could we possibly do away with the User-Agent header, or reset it to a simple “Chrome 150.01”?


I vaguely remember plans to make the user agent simpler but I can't find anything that matches with some quick web searching. The most relevant article I could find was from 2013: https://hacks.mozilla.org/2013/09/user-agent-detection-histo...



Meh. For all the silliness, it’s not that hard to parse one for the main purpose it should be used for, which is determining in aggregate what platforms your users use. As such, we still need things like OS in there anyway. So it wouldn’t get quite that short.

Also I’m amused checking mine that the user agents still say “Intel Mac OS X” even on Apple silicon. I guess they were afraid someone’s parser would think we are on PowerPC without that!


Look at all the comments insisting that the way Microsoft does it is the correct, superior way. How could we do away with it then?


"We" did. Microsoft didn't. Not unexpected.


Is this part of a fan fiction where MS isn't amazing at legacy compatibility?


I think their BC is overrated. Wine manages to do a better job.


This is also very good for security. Correctly dismissing an API call means these programs aren't able to go off and do extra naughty things.


Wouldn't it be simpler to just create a "Save to PDF" printer and use that in the Xbox? This way the API stays compatibile, and it actually makes it useful


The only reason an X-box doesn't support printing is because Microsoft has defined it as such. A x-box is just as capable to print as the Windows machine in the next room over from a hardware perspective.

Which means this "solution" to a stupid, self-created problem is stupid. I bet this workflow will lead at least a handful of people to ask "How do I add a printer to my X-box?" instead of "Fuck the app crashed, better not do that again."

Microsoft has so much stupid, corporate driven decision making. Can't wait for it to follow in IBM's footsteps.


I missing what the magic is here.

This seems like a long way to go for “we know that this device is an Xbox and Xbox doesn’t support printing, let’s tell the user”

Only it doesn’t tell the user. It leads them down a path implying implementation is possible.

On the other hand, I now know why so many issues I’ve troubleshooted on MS products end in tears and complete confusion as to why they wouldn’t just say “this is not a feature you can use on this device.”


> This seems like a long way to go for “we know that this device is an Xbox and Xbox doesn’t support printing, let’s tell the user”

You're missing the fact that Xbox can run apps developed for (desktop) Windows, and that the scenario in the article is about the platform <-> end user relationship and does not involve the app developer at all.


Ok, appreciate the insight.

Doesn’t the platform: 1. Know that is a windows app 2. Know that it is Xbox

So it could override the “print” request with a user appropriate notification?


I agree. The author's description of what is "reasonable" sounds like a blueprint for many of my late nights struggling with Windows:

"apps that assume that printing works will still behave in a reasonable manner: You’re just on a system that doesn’t have any printers and all attempts to install a printer are ineffective."

Maybe the underlying assumption is that the users will give up before spending an "unreasonable" amount of time on these tar pit features.


Microsoft’s MDM APIs will return a 500 (server error) on a VM if you try to get a list of wireless networks, instead of the saner approach of returning an empty list. The same APIs will return a 418 (I’m a teapot) if you mistakenly try to add an already-existing setting, instead of just updating it as one might expect. They get points for originality, but don’t follow the advice in this article.


Microsoft has around 238000 employees according to Wikipedia. That they are not all strictly following Raymond Chen's latest blog post isn't surprising.


Hmmm I see and appreciate the idea behind this. That said, it seems confusing for the user to be shown an empty list of printers if no printers can be installed on the platform. In my opinion, it would be preferable to show the user a dialog that says "This platform does not support printing" and, once they dismiss the dialog, inform the program that the user cancelled the print action.


I agree, using the empty list to communicate to the user the situation is making an assumption about the user. A lot of users have never set up or dealt with printers ever. I can say for sure that an empty list of printers would confuse a lot of people in my household.


Slightly tangential, this reminds me of how to `sleep` in JavaScript without using async: https://stackoverflow.com/a/37575602


Exception safety guarantees have been around for decades and were originally defined by David Abrahams who was on the C++ standards board.

As the author is a Microsoft employee I'm a little surprised no attribution or reference to the original author of (the levels of) exception safety guarantees which his article partly describes.

Raymond Chen (article author) is refering to the "no throw guarantee" in his article as opposed to one of the other outcomes https://en.m.wikipedia.org/wiki/Exception_safety


> Well, the wrong thing to do is to have the printing functions throw a Not­Supported­Exception. The app that the user installed on the Xbox was probably tested primarily, if not exclusively, on a PC, where printing is always available. When run on an Xbox, the exception will probably go unhandled, and the app will crash.

Exceptions are such a catastrophically bad idea in almost all cases.

It is absolutely infuriating as a programmer to call a function and not know if it can throw and, if it can, not know what it can throw. It’s a disaster.

I so desperately wish that C++ had Rust’s Result type and pattern matching. std::optional and std::expected are kinda sorta ok, but you really want compiler enforced pattern matching.

What a tragedy.


> if it can throw and,

noexcept.

Granted, it may not have the annotation but still not throw in reality, but a Rust function can also declare a Result return type but never actually return an error.

> if it can, not know what it can throw

How do you square that with backward compatibility?

If you declare what you can throw, what do you or any of your transitive dependencies do when they want to change their implementation in a way that makes a new error a possibility? Either you shove it all into an UNKNOWN error that you hopefully declared from the get go to be future-proof, or you break all your downstream users every time. So either no compatibility, or over time your API converges to a meaningless UNKNOWN error code for almost everything and a bunch of legacy error codes that are never used.


I’ve never, ever seen a codebase that reliably used noexcept.

boost and Python are my arch-nemesi because they make heavy use of exception errors and it makes the APIs an absolutely miserable nightmare to use.

> How do you square that with backward compatibility?

Huh? The same way normal code handles changing function arguments or return types? I have absolutely never relied on exceptions to “future proof” return error types! Yikes.

The only thing I have ever used exceptions for is to escape bad input/data. It gets trapped internally in the “private” API and same result types are returned through the public API.

I would much rather have a return type of Result<T, Exception const*> than T but also maybe it throws or maybe not and you almost definitely forgot to check which is why people do filthy filthy hacks like the OP article.


> It is absolutely infuriating as a programmer to call a function and not know if it can throw and, if it can, not know what it can throw. It’s a disaster.

Every nontrivial function can fail (in C even a unary operation on an int), it's just a question of whether and how the caller is informed, how easily the failure is to ignore and continue processing in an undefined corrupted state, and what percentage of the code ends up being dead branches for impossible-but-unprovable error paths.

> I so desperately wish that C++ had Rust’s Result type and pattern matching.

I'm a fan of Rust too, but what do you think panic() is?

Rust has no concept of code that always succeeds. It's all-but impossible on current CPUs.

https://github.com/search?q=repo%3Arust-lang%2Frust+path%3A%...

https://doc.rust-lang.org/std/result/enum.Result.html#method...


I wish the concept of dev mode and prod mode were baked deeper into all language runtimes/libraries.

e.g. before going to production with real users these cases should error as hard as possible, including potentially logging crashing the program to make the program errors super visible. Then in production it should largely log these things in error logs and keep chugging along.

And not like an environment variable with conditions. Something as first class as changing the standard exception and fatal calls behaviors.


This is also like Null Object or Special Case pattern. It simplifies error handling, and because error handling code is often poorly tested it ends up being a big source of catastrophic failures. Making illegal states unrepresentable, or as John Ousterhout puts it: define errors out of existence: https://wiki.tcl-lang.org/page/Define+Errors+Out+of+Existenc...


Why /wouldn't/ I want to print something from my Xbox?


The printer drivers don't run on XBox. XBox isn't exposing all of the legacy Win32 APIs and driver models available in desktop.


It's an x64 CPU running most of Windows with plentiful and fully supported USB ports. Why CAN'T I print from my Xbox? I can print with my phone, so why not my Xbox?

I'm sure there's something about "windows print subsystems are pretty terrible and we should excise them from anything we can" and "reduce code to reduce bugs" but like.... There's no technical reason it can't


You go to print a document. Your printer is temporarily unavailable. The print job hits the spooler and sits in a queue. You get bored and launch a game. The printer becomes available. The print driver has to convert the job to PCL or whatever proprietary format the printer uses. Your game hangs or even worse crashes because it's not really designed to run with background tasks on the same cores.

Who do you blame, especially since the usual diagnostic tools of a PC with a full operating system aren't available?

It's a feature very few people will use with lots of sharp edges that people accept on a PC but would find intolerable on a video game console.


It's not running "most of Windows". In particular, as far as I know (no insider knowledge), it's not running any of the Win32 APIs (USER, etc.). So that rules out any printers which require coordination with their desktop app (which, to be honest, to get full functionality is still a shockingly high number of them). It's highly unlikely the XBox hypervisor implements any of the printing APIs, even UWP because this is a video game console, and not only does almost no one own a networked printer, an even smaller group of essentially no one has a printer, opens documents on their video game console, and wants to print them.

Features aren't free. What Xbox feature would you drop to have an engineer go implement printing APIs on them? Is that the best use of their time?


Due to the input device most people will use (controller), apps that work best on Xbox are those used to consume content like photos or videos.

You might be viewing something and want to print it, but that's clearly not desirable enough for Microsoft to build print functionality into the Xbox UI.


I mean, it has USB ports. If I can plug it in, I'd like to be able to use it _somehow_ , even if that means installing another app that does direct port/device access or w/e . ie, it should be possible (but not necessarily super easy)


The explicit point of video game consoles is to be a locked down experience, not a PC. Hardware access is generally used for piracy, which game developers do not like.


There are widely used practices for API design and versioning that work well today. While this article's kludgy approach to backward compatibility may have been passable a few decades ago, this is a terrible way to approach the problem in 2024, specially with services & APIs being deployed & distributed across platforms.

The article illustrates how *not* to build APIs.


> the function for installing a printer can return immediately with a result code that means “The user cancelled the operation.”

I hope this is never shown to the user, because one of the most infuriating things that can happen is when the computer tells me that I did something I actually didn't.


It would be unlikely that it would be, since to any properly implemented app, the fact that the user cancelled is not an error since it thinks you did it yourself on purpose.

On the other hand, I recall a few years ago (in the days of one of Apple’s least stable Mac OS [X] releases) seeing the message frequently after a random kernel panic “You restarted your computer because of a problem.” And I would be pretty ticked, saying “Nope! YOU restarted yourself. 0% of this was me. I was sitting here and you just died and rebooted.”

They changed it to use passive voice instead, a year or two after that!


Or more broadly, don't do something unbidden on my behalf then complain when it doesn't work. I swear 75% of the times I've daydreamed about a return to a single-tasking OS like DOS was on account of software trying to 'help' me.


Doing nothing correctly sounds like hard work. I guess I'll try it out sometime later when I have more energy.


This starts with an Xbox not being able to print, while being able to run computer applications. The correct solution is not to have that. There is no graceful way to recover otherwise, no matter how "inert" you are.


From the title alone, I initially thought this would be about meditation.


Making it a linker error doesn't even seem to be considered. Xbox is a separate target so a recompile is needed anyway ...


No, it's not - that's the point of the Universal Windows Platform - compile once, put in store, run everywhere.

This also isn't just about new platforms. If you have a desktop operating system and want to change the behavior of an API in a future version, you have to do this same process.


> “I asked for a widget, and you gave me one, and then when I showed it to you, you said, ‘That’s not a widget.’ This API is gaslighting me!”

The entire point, it should be noted, is to gaslight the app. But the API must be good enough at gaslighting that the app doesn't discover the lie.


As a Platform Engineer who has to work with Azure on a daily basis, I am so tired of their APIs and services making exceptions left and right, sometimes for their own shitty clients. The result is a Patchwork product suite, services never work as expected but deviate from their documentation (or rather what they are claiming is their documentation).

The Daily Azure shit Mastodon account has more than enough examples of this. For example https://azsh.it/167 or https://azsh.it/107

This article made me realize while Azure is the way it is - unreliable and broken.


> The idea here is to have the printing functions all behave in a manner perfectly consistent with printing being fully supported, yet mysteriously there is never a printer to print to.

What? Why would you ever do this? This post screams of "can't see the forest from the trees"

Sure, now you don't have your app crashing, and instead you have this weird state of seeming like you can print but ultimately can't, wasting users time and perhaps frustrating them even more.

Why not literally just show a dialog like "printing is not supported from an Xbox"? Easy to develop, easy to understand... everyone wins.


I'm sorry but that code sample is an incomprehensible eyesore.

And I've written PHP4.


Windows headers like uppercase. They also like very explicit types, as far as the language accepts them, of course. For example, HRESULT really is just a 32 bit integer with special rules (top bits set subsystem that cause the error, bottom bits set error code, hence the conversion function for best practice).

Stripping out the Windows types and compile-time validation and the wrappers, and picking non-Windows error codes, you can turn the code into more Unix-like C++:

    int32_t CreateWidget(int32_t* widget)
    {
        *widget = nullptr;
        return ECANCELED;
    }
    
    int32_t GetWidgetAliases(wchar_t* aliases, uint16_t capacity, uint16_t* actual)
    {
        *actual = 0;
        return EBADF;
    }
    
    int32_t EnableWidget(int32_t widget, bool value)
    {
        return EBADF;
    }
    
    int32_t Close(int32_t widget)
    {
        return EBADF;
    }
    
However, this code may not function if you're building for 32-bit Windows and it may not work on every compiler; it just assumes certain bit sizes that the API only guarantees in the form of typedefs.


What's crazy is that I didn't even realize it until you pointed it out. I've been doing Win32 for so long it's like reading the green symbols in The Matrix. This all looks "normal" to me.


Besides being unreadable, it is well known that Win32 API code is unwritable. It is only copy/paste-able.


throw checked exception so that xbox will have to handle the exception. xbox implementation can donothing if they want.


Sometimes this kind of error handling is the cause of program slowdowns. So the API fails, but the program retries anyway, and so fails again endlessly. The user doesn't see anything from this happening, only that "the app is slow". Windows is plagued by this kind of behaviour. Its both what the article suggests can cause this, but throwing and ignoring exceptions can have this effect too.

The goal, IMO, would be to force the app not to try (or not to try once it failed) something that is bound to fail.


"The idea here is to have the printing functions all behave in a manner perfectly consistent with printing being fully supported, yet mysteriously there is never a printer to print to."

this is exactly the kind of stupid shit that makes me hate using anything from microsoft. on what planet is this desirable behaviour? is it beyond microsoft's capability to just show a message saying "Printing is not available on Xbox"?


It's a crap analogy. Why would you expose a printing API on a device without printing support? Just ifdef it out on the build.


How about an app originally designed for iPhone but is running on an iPad? iPhones can make calls, but iPads can't. Sure, a properly designed iPad app wouldn't try to use the phone functionality, but what if the developer is too lazy to develop a dedicated iPad app? Surely a crappy iPhone app running on iPad is better than no app at all?


Wouldn't that be part of Apple's app reviews?


Only if you try to publish it as an iPad app. See also: https://hacknicity.medium.com/how-iphone-only-apps-appear-on...


There are plenty of apps already in the store. Apple wants to launch their new device and have tons of apps available. The best way to do that is for the apps to just run, not to require millions of developers (plenty of which no longer exist) to rebuild.


> Surely a crappy iPhone app running on iPad is better than no app at all?

Bogus comparison. Non-crappy apps are a thing.


There are many forms of "crappy". Developer hygiene is one bar; user functionality is another.

"Crappy" here refers entirely to developer hygiene, which the user does not care about at all.

If the platform changed and Angry Birds crashed, the customer would not accept "but look at all of these other Angry Birds clone games still available" as an answer, they want the app they are familiar with.


> If the platform changed and Angry Birds crashed

Angry Birds doesn't print AFAIK.

The scenario is an app being run on a platform that doesn't meet its declared system requirements.

If an app requires Windows, and customer tries to run it instead on Xbox OS, then he should be surprised it even launches. He should not be surprised if it crashes on print.

> customer would not accept "but look at all of these other Angry Birds clone games still available" as an answer, they want the app they are familiar with.

Then he'll have to run that app on the OS it requires. He's free to sent to MS his complaint that Xbox does not run that OS.


https://en.wikipedia.org/wiki/Metaphor

Telling customers "well go use this other platform" is not an effective way to build or grow a platform.


> Telling customers "well go use this other platform" is not an effective way to build or grow a platform.

Honesty is the best policy.

Telling customers they should expect to run apps that don't support your platform is not honest.


When you have a platform, apps aren't always being rebuilt for it.

There is no "build" because the source code was lost when all of the company's assets were sold off in 2002.

There is no "build" because the developer made a game, put it on your app store, moved on to the next game and has no interest in supporting this game that isn't providing any significant new revenue.

There is no "build" because this is FooManager 6.0, the company that makes FooManger wants everyone to buy FooManager 7.0 and isn't making any further changes to 6.0.

etc. etc. etc.


It's an option, but it has its own downsides. It's a cross-platform API.

Someone wants to show some guests some of their photos and videos on their TV through their Xbox. Unfortunately they can't because their app (eg Samsung Gallery or iCloud or whatever) included a print button somewhere.

And with these inert functions, if Microsoft one day adds printing support to the Xbox, it'll just work in the photo app without any update.


Because then you're making every developer make a special build for every device. Most developers aren't going to care enough to make a dedicated Xbox or tablet build. You're just going to make the platform completely dead. It would be much better if all pre-existing apps could mostly run on them.


"The idea here is to have the printing functions all behave in a manner perfectly consistent with printing being fully supported, yet mysteriously there is never a printer to print to."

This must be satire. Otherwise I can't comprehend how something as infuriating as this could be presented as a good or smart thing to do UX-wise


No, this is a guy who has been one of the architects of Windows for more than 30 years giving you hints about how they achieved their reputation for amazing backwards compatibility. He really, really knows what he's talking about.


No it's not satire. It's a demonstration of the excellence in backward compatibility and cross-compatibility that Microsoft has always been known for, and that so-called modern players like Google and Apple don't take seriously.

Just because an XBox can't print doesn't mean that an app that prints shouldn't run on XBox. It should just mean that the printing function shouldn't run. How to achieve that is exactly what Raymond Chen, a Microsoft and Windows veteran, is trying to explain here.


If the two options are "this app can't run on your Xbox" or "this app runs on your Xbox, but the printing functions don't work and some of the messages are a little weird", which option do you think users would prefer?


But the first option is not "this app can't run on your Xbox". It is "This app possibly cannot run after trying to print".


Code like this often runs during application startup. It's not just printers.


The situation is "What should happen if an app tries to print on an Xbox?". I do not believe code that tries to print often runs on app startup.


Printing is one example of this pattern - there are plenty of reasons APIs end up unsupported

Printing may also run on startup. Consider software for a vinyl cutter which looks for the device when beginning.


> Printing is one example of this pattern

Then my point stands.

> Consider software for a vinyl cutter

On Xbox?? Good grief.


So what, you crash the app? What if there's no API to say "there's no printing on this device"? What is the difference between a device where printing isn't supported and a device where a printer isn't set up yet? Showing an empty list of printers isn't a bad solution, frankly.


Ahh I completely misunderstood the article from a quick reading. It seems like the only solution to a tricky problem.

Thanks to anyone who replied to me pointing that out. It's a good example of when one should read the article more closely before commenting!


What do you suggest as an alternative?


Perhaps you missed the context in which it was made clear that this imperfect solution was still less bad than all other options.

It seems the point resembled: 'this device doesn't support printing, don't return obscure, unhelpful or crashing errors; return something that makes sense so that the user can figure out and move on'. I.e.: Fail gracefully.


I wouldn't call creating mystery failing gracefully. As a user I would prefer a full crash to the application gas lighting me by suggesting there's something wrong with my setup (we can't find your printer vs you're not allowed to print).

If anything creating mystery about what the app is doing is the direct opposite of good UX.


User spends two hours creating content. User hits print.

1. App crashes back to the desktop/Home Screen/etc

2. App can’t find any printers. User cancels and saves the document, prints elsewhere.

You really think option 1 is better?

Also, none of this precludes the ability to display a message. He’s talking about the system calls themselves and how they should respond. I suppose if the call for the “Add Printer Wizard” is called, it could not only return the “user cancelled it” status but also display an error message. It depends on the implementation details and whether someone probably 20 years ago foresaw the need for a modal but not fatal system error message to be triggered by that API call. Which again is not in the today developer’s control.


> 1. App crashes back to the desktop/Home Screen/etc

Why do think it would crash, rather that simply return to main loop?


It might return to the main loop if you throw a NoPrintingOnXboxException… if and only if the author of the app has decided to catch a broad enough exception in that exact place in the code, and handles it gracefully. Good practice to always handle any exception that might be thrown, but it’s not always obvious in the past where there might be a chance for an exception to be thrown. For instance, the printing subsystem itself can’t be missing, can it??

So anyway, the platform vendor can’t be sure the above situation is perfectly handled by every app, so the entire point of the article is “given you must technically comply with the published API specifications, how can you construct the least harmful and least disruptive response to every request sent to this fully-removed system component.”

This whole exercise is basically constructed in order to usually guarantee the outcome you’re suggesting: to cause the app to just return to its normal functioning without doing the impossible thing.


So it 'simply returns to main loop'. I.e., the user hits [Print] and then it maybe flickers and goes back to the home screen.

How in heck is that more useful than App reporting that "I can’t find any printers"?


Because "I can't find any printers" suggests that printing is possible if only you set up your printer correctly, rather than suggesting the print function doesn't work.

By showing that no printers can be found the app is misleading the user to think there's an issue external to the app that they need to solve themselves.


> the user hits [Print] and then it maybe flickers and goes back to the home screen.

And reports the exception.


The idea is to accommodate apps that just didn't handle the exception, or handled the exception by crashing, probably because they only tested the app on a PC, where printing was always available.

> Well, the wrong thing to do is to have the printing functions throw a Not­Supported­Exception. The app that the user installed on the Xbox was probably tested primarily, if not exclusively, on a PC, where printing is always available. When run on an Xbox, the exception will probably go unhandled, and the app will crash. Even if the app tried to catch the exception, it would probably display a message like “Oops. That went badly. Call support and provide this incident code.”


> probably because they only tested the app on a PC

If they made an app only for PC, why would they test it on Xbox??

If they wanted their app to run on Xbox, why would they not make an Xbox version, and test it there??

RC's scenario is taking an app made for only Windows PC and running it on Xbox. I wonder if he has found even one example which permits this in the licence.


> RC's scenario is taking an app made for only Windows PC and running it on Xbox. I wonder if he has found even one example which permits this in the licence.

I don't know what program he would be talking about, but I think if Raymond Chen is writing about something, it's usually because it is a real problem that was encountered, even if he's writing about it as if it was hypothetical to avoid naming the software in question.

He generally avoids naming non-Microsoft software he's found bugs in.


> if Raymond Chen is writing about something, it's usually because it is a real problem that was encountered

I don't doubt that. But I do doubt this problem can be encountered except by abusing the app.

> He generally avoids naming non-Microsoft software he's found bugs in.

Not relevent, since this failure of Xbox to run a Windows app is not a bug.


> if Raymond Chen is writing about something, it's usually because it is a real problem that was encountered

I don't doubt that. But I do doubt the problem can be encountered except by abusing the app.

> He generally avoids naming non-Microsoft software he's found bugs in.

Not relevent, since this failure of Xbox to run a Windows app is not a bug.


> I.e.: Fail gracefully.

There's no grace in misleading the user and wasting his time.


The alternative is that the app fails to run at all. Doesn't seem like satire to me.


Or worse, crashes at a random spot because it tried to initialize the printer stack.


Anyone who has spent some time with vintage or otherwise older software (and even some new stuff) should have experienced a "don't do this, it explodes" - often the cause is something akin to what Raymond is pointing out. The software asks for something, gets back an answer it can't handle, explodes.


MS being okay with the user clicking somewhere and never getting any reaction out of it explains many of my interactions with Windows 10.


if possible, throw checked exception which must be handled.


And they ask why we're cynical. I'm about done with this whole "personal computing" fad.


Your ecosystem has gone so complex that you can't test it anymore. So instead of handling errors properly you suggest to implement a convoluted user flow that offers always failing actions (install a printer when there's none available).

If that's really the suggestion of product and engineering leadership at MSFT no wonder all their products...err...work as designed.


Not at all what he is saying. Microsoft has no problem testing their printer function across all platforms in their apps and removing the print button on platforms where it's not supported. Ideally, everyone would do this.

This is for other developers who are writing 3rd party apps for Microsoft's platforms and who don't always test perfectly. They may have written their app primarily for Windows and didn't consider what happens when someone installs it on their Xbox and clicks "print". In that case, the API should "just work", instead of crashing with an error message.


>Your ecosystem has gone so complex that you can't test it anymore.

An operating system with billion+ install base, and millions of developers tends to be complex. I'm not sure what you're proposing here, have your platform/software be more niche? Somehow get all of them to fall in line?

>So instead of handling errors properly you suggest to implement a convoluted user flow that offers always failing actions (install a printer when there's none available).

How are you going to "handle errors properly" if the publisher of the software in question went out of business?


What is "your ecosystem" here? Part of running a platform is that the code running on it is written by other people, not you, and that your customers will be relying on that code.

When the software your customers are relying on breaks because of a change you made, it doesn't matter whose "fault" it is. It's broken, it broke because of something you did, and you have burned customer trust - not the trust of whoever wrote the software you believe is "wrong" or "to blame", trust of your platform and company.


It is so obvious from reading these comments here who is not, and would never ever want to be, a platform engineer. It’s hard for some people to grasp that you need to not only interact with, but thoroughly accommodate, software written by others whom you don’t control (often due to the one-way direction of time flow).


From my experience in other MS orgs, this was the prevailing approach. There are masses of bandaids on top of systems that have organically evolved over decades. Leadership is generally promoted from within so have a blind spot to how organisation incentives lead to these technical outcomes.


Good: average apps continue to work as expected.

Bad: good apps can't know what's supported or not.

What's missing from the article is adding a way for apps to detect and handle this behavior. (Using the printer example) There should also be some API that tells me "printing is not supported on this platform" somehow. If I want to be a good software developer I should hide the print button in the UI in a very predictable way.

It's great that if I actually try to print nothing happens as expected. It's bad if I can't detect that printing would never work, and I should be able to do that via at least some function call that doesn't magically noop.


From the article:

> Now, you probably also want to add a function to check whether printing even works at all. Apps can use this function to hide the Print button from their UI if they are running on a system that doesn’t support printing at all.


Somehow I missed that. Thanks!


Wrong, errors should not go unnoticed, let alone helping them to propagate. Cascading effects should be kept on a short leash. System takes one step in the wrong direction, kill it. The two most miserable things are, things not happening and there's no feedback on why, and, the other extreme, when things are overengineered and no one can predict where problems might cascade to.


lord grant me the confidence of someone who reads a thoughtful explanation of a problem and its solution by Raymond Chen and responds with "Wrong, "


It's hilarious, Chen has been doing this right - on the bleeping internets for all to see - for thirty years and we've greenhorns going "Nah, mate, you're doing it wrong."


Maybe you should build an operating system from scratch, keep building it for more than 25 years and then come back to revise your comment?


This mindset is even less ethical than it seems, and I'm not surprised to see it present at microsoft.


What do you mean by "ethical" here, and why is it unethical to preserve ABI compatability?


I didn't say it's unethical to preserve "ABI compatability." It's the software equivalent of the Chinese government gaslighting everyone while they wait for the dancing grannies to get the hint and go home. It is, in fact, the exact same technique.

And not only that, we're fast approaching the day where we all power on our PCs to discover that you can login with any user you like. And it gives you the list of all users who have a one drive account.


It's nothing of the sort. They provide APIs to check if functionality is supported and encourage their use. Helping users deal with apps that weren't written to deal with them isn't lying to users.


> why is it unethical to preserve ABI compatability?

Straw man. What's unethical here is deceiving the user.


There is no deception. There are no printers, and that's what the API returns.


The deception is concealment of the fact printing is unsupported. Nk printers is merely a cover story.

"Not­Supported­Exception" is there for a reason.


Nothing is being concealed. If you want to know if printing is supported, call IsPrintingSupported. The information is there, the API is there.


The one deceived is the user. He does not have the option of calling an additional function.


This is obviously how they made their recent hit game "authenticator loop" that we all loved so much for a while there, for instance.


I understand the logic here, and I'm aware Microsoft has a large number of convoluted backward-compatibility requirements, but this seems like drinking to solve your problems and just putting off the inevitable hangover. To be clear: what you're doing here is lying to the user and the developer. Maybe that's justified in isolation, but now this lie is one more bit of "hidden state" you have to keep track of in further development and integration testing. And just like in the real world, lies have a tendency to compound on themselves until you're completely lost in them and have no idea what reality is.

I have a feeling that "solutions" like this are part of why an increasing number of my computing problems take the form of, "I tried to take an action, nothing happened. No error, no activity, nothing.", and are impossible to debug or diagnose. UX designers made themselves terrified of ever showing an error code to a user, but they took that and replaced it with a world where your shit just doesn't work, and when you try to figure out why, all the OS does is shrug.


So what's your solution then? Break all apps simultaneously that do not have extensive tests for gracefully handling cases that were impossible when they were created?

This is not weird "hidden state" on the implementer's side. It's a straightforward dummy API and all you need to do to test it are a few straightforward asserts that it returns the correct dummy values and doesn't crash.

> I have a feeling that "solutions" like this are part of why an increasing number of my computing problems take the form of, "I tried to take an action, nothing happened. No error, no activity, nothing.", and are impossible to debug or diagnose.

That's precisely not what this is. The whole point of the article is to do nothing correctly. Presenting an empty list of printers is consistent with a PC that simply doesn't have any printers installed. A wrong thing to do would be, for example, presenting a dummy printer that accepts jobs but of course never prints anything.

You don't break the users of your API, period. That shouldn't be controversial. Unfortunately, too many people seem to think they need to do everything over every couple of years only to produce a solution that is no more extensible and resistant to bitrot than the one they're replacing.


> So what's your solution then? Break all apps simultaneously that do not have extensive tests

No test required. Just try... catch.

> for gracefully handling cases that were impossible when they were created?

You can never know they are impossible. That is why you have a top-level try...catch.


> No test required. Just try... catch.

That doesn't even make any sense. Where on earth would you insert a try...catch?

So many people commenting on this article seem to have fundamentally misunderstood what the situation/scenario even is, which is made more jarring by the fact that so many others seem to have gotten it just fine.


> So many people commenting on this article seem to have fundamentally misunderstood what the situation/scenario even is

Agreed 100%. Those people have overlooked that this is about attempting to run apps on an unsupported OS. And when printing, the OS attempting to gaslight the user into thinking the fail is his fault for not connecting a printer.


The apps are being run on a supported OS which doesn't have all features. Your framing is bizarre.


If this app supported Xbox OS, then how come:

"The app that the user installed on the Xbox was probably tested primarily, if not exclusively, on a PC"

??

Note that Xbox OS is not Windows. If an app says "requires Windows", then it means requires Windows.


How do you somehow both have a strong opinion about "deceiving users" and completely fail to understand the difference between a platform/OS and a device?


This is about 3rd party apps that Microsoft has no control over.


As far as alternatives to what the article suggested go, I think the ideal solution would be to have a compile-time error, so the developers never even get as far as having their printing code try to run on the Xbox. And since it's a compile-time error, there doesn't need to be any kind of runtime error handling or cost either.


Except now you have lost the ability to run all the software that cannot be fixed and recompiled for whatever reason.


You could still offer the mocked APIs, but have them be opt-in. Also, having the compiler throw an error doesn't mean that an older, already compiled executable won't work.


> Also, having the compiler throw an error doesn't mean that an older, already compiled executable won't work.

And when the older, already compiled executable calls the API, how do you make things "work"? That's exactly what the article is about.


Apps aren't being compiled here. Apps already exist and new platforms and platform functionalities are being made available.

Launching platforms is an eternal chicken and egg problem: You want to launch a new platform. Users want apps before they buy into the platform. Developers want users and a guarantee they will spend money before investing time and money building apps for the platform. If you're really really rich, you can literally pay developers to write apps for you, but ask Microsoft how that went with Windows Phone.

Instead, the most reliable way (I said most reliable, not reliable) is to leverage an existing group of apps onto your platform. Maybe you have a phone ecosystem and want to get into tablets. So you take the already existing phone apps in your store and let them run on your new platform.

There is no recompiling. There is no build.

There is no "build" because the source code was lost when all of the company's assets were sold off in 2002.

There is no "build" because the developer made a game, put it on your app store, moved on to the next game and has no interest in supporting this game that isn't providing any significant new revenue.

There is no "build" because this is FooManager 6.0, the company that makes FooManger wants everyone to buy FooManager 7.0 and isn't making any further changes to 6.0.

etc. etc. etc.

Binary compatibility is what matters. Nothing else is of particular significance.

In addition, if recompiling an app for your new platform yields compile errors and requires work (as opposed to targeting a new platform version in a manifest and just hitting build), developers on your platform are significantly less likely to spend the time to do so.


This resonates with me. My computers used to crash at the app level, OS level or hardware level.

Now when something goes wrong the system just kinda gets lazy and stops working. But it won’t crash.

I’ve had my mac pinwheel on the login screen. I can still access the shell and file shares remotely, and even screen share to a logged in user.

But login.app refuses to crash so it’ll just pinwheel.

I’m glad I never forgot to turn things off and on for troubleshooting :(


I have a suspicion that "number of crashes" got badly Goodharted inside major OS vendors. After all, you can "prevent" most crashes by just having a top-level "catch(Exception e) {}" handler, which of course just leads to the program doing nothing instead in an un-debuggable way, but hey: crashes went down! KPI achieved!


My experience is that macOS especially really REALLY absolutely hates when the Internet goes sideways - not actually down, but really bad packet loss; DNS starts being slow and failing sometimes but not completely ... then you enter hell.

Next time it happens try turning network connections all the way off.


as the article says, the correct solution is to provide an API that applications can access to check if the functionality is offered at all.

functions that return correct null responses isn't the ideal behaviour, it's the fallback for when you're already off the happy path.


I think there's a difference between an API that can be used to check if functionality is available, and an API that must be used before that functionality is offered to the application. E.g.

    CheckForPrinting : () -> Maybe PrintToken
    ShowPrintDialog : PrintToken -> Dialog


To be fair, sometimes you get "Oops, an error occurred, LOL!"




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: