upvote
I feel like I'm the only person in the world who would rather write ugly win32 jank for the rest of my days than ever having to touch an "elegant" or "well structured" Cocoa codebase. In win32 if you want a button you call a function and pass a hande, in the Apple world you first subclass 7 interfaces in some unreadable Smalltalk-wannabe syntax and pray you don't need to access the documentation. And of course they constantly change things because breaking backwards compatibility is Apple's kink.
reply
After bouncing around GUI toolkits (from win32 to SwiftUI) and web for 30 years I have simply run out of fucks. They all suck. Each in their own unique way. Apple aren't worth singling out - they are just their own special isolated variant of it.
reply
Tcl/Tk is pretty good in terms of rapid development. Unfortunately it has stagnated quite a lot over the years.

Gtk on the other hand is absolutely terrible and its developers don't help by completely rewriting things every few years and breaking all existing code in the process.

reply
Tcl/Tk was also popular in certain niche products, like in RF test equipment.
reply
It's still quite big in EDA (electronic design software).
reply
But, why? It's been 30 years. You'd think somebody would have figured out how to make a decent GUI toolkit or framework.
reply
Have you tried WinForms? It isn’t the latest hotness so Microsoft has to be dragged kicking and screaming to support it in current VS, but they were forced to do so because corporate developers still have some clout.
reply
I still think that WPF was the peak desktop UI framework. Extremely powerful with lots of small composable primitives, can easily do declarative but drop into more traditional event-driven imperative style where it makes sense.
reply
They generally get the design right after some mistakes and are stabilizing it, when the new UI designers take over and want to re-do it from scratch.
reply
AvaloniaUI + MVVM toolkit.
reply
We just built layers of shit over the ones we have.
reply
This is patently false. To add a button to your UI, you open your window’s nib file Xcode/Interface Builder, click the plus button on the toolbar, and add a button. Then you control-drag from the button to File’s Owner and choose the method that you want to invoke when the button is clicked. Done.
reply
And this already worked in OPENSTEP, like 30 years ago.
reply
Programming with GUIs?
reply
Yes, generations of Mac and Windows programmers have used GUIs to create their GUIs. Visual Basic, MFC + App Studio, .NET + WinForms, Interface Builder…
reply
Why wouldn't you program a GUI with a GUI if one is available? Avoiding the use of WYSIWYG editors when making GUIs is like avoiding the use of musical instruments when writing songs.
reply
That feels like quite the exaggeration. If all you want is a button, all you need to do is initialize an NSButton and then tweak a few properties to customize it as desired.

If you want something more custom, subclass NSControl and you’re off to the races.

And if Obj-C isn’t your cup of tea, one can use Swift instead, even in a codebase that had been only Obj-C prior.

reply
You can now use SwiftUI, which is, as of the latest version, quite stable. They used to change things a lot between releases a few years ago, but nowadays you don't need to refactor your code every year. Only issue with it is that it's iOS first, so you may need to fallback to AppKit (Cocoa) to implement more complex elements.
reply
How to add a button in SwiftUI:

    Button(“Click Me”) { buttonWasClicked() }
reply
Sorry, but this is simply just misinformation.

If you were doing "classic" Cocoa in the way it was intended, you wouldn't need to subclass anything for a simple button.

You wouldn't even need to write a single line of code, you'd just instantiate said button in Interface Builder, hook it up to a delegate (e.g. a window controller) and off you go. You can create a hello world example with a handful lines of code.

And even if you'd rather create the button programmatically, it's not much more involved.

Sure, if you're coming from Win32 and expect to program Cocoa without learning Cocoa, you're out of luck. But I guess that applies to all frameworks.

reply
What are you talking about? In Cocoa if you want a button you drag one in via Interface Builder. You don't even need to write any code. If you want it to do something, you type the name of the function it should call.
reply
I'm probably another, but I have never done any professional Win32 work. You know, those kind of jobs are rare now and I doubt they want anyone without experience.
reply
This is such a wonderfully beneficial comment to the HN community. It should get an award.
reply
To me this kind of "no need to change anything" implies stability but there's a younger cohort of developers who are used to everything changing every week and who think that something that is older than week is "unmaintained" and thus buggy and broken.
reply
One of the earliest security issues that I remember hitting Windows was that if you had a server running IIS, anyone could easily put a properly encoded string in the browser and run any command by causing IIS to shell out to cmd.

https://learn.microsoft.com/en-us/security-updates/securityb...

I mentioned in another reply the 12 different ways that you had to define a string depending on which API you had to call.

Can you imagine all of the vulnerabilities in Windows caused by the layers and layers of sediment built up over 30 years?

It would be as if the modern ARM Macs had emulators for 68K, PPC, 32-bit x86 apps and 64K x86 apps (which they do) and had 64 bit Carbon libraries (just to keep Adobe happy)

reply
Better to have known unknowns, than unknown unknowns.
reply
I think its at least as much of a working environment preference.

Once I became experienced enough to have opinions about things like my editor and terminal emulator... suddenly the Visual Studio environment wasn't nearly as appealing. The Unix philosophy of things being just text than you can just edit in the editor you're already using made much more sense to me than digging through nested submenus to change configuration.

I certainly respect the unmatched Win32 backwards/forwards compatibility story. But as a developer in my younger years, particularly pre-WSL, I could get more modern tools that were less coupled to my OS or language choice, more money, and company culture that was more relevant to my in my 20s jumping into Ruby/Rails development than the Windows development ecosystem despite the things it does really well.

Or to say differently: it wasn't the stability of the API that made Windows development seem boring. It was the kind of companies that did it, the rest of the surrounding ecosystem of tools they did it with, and the way they paid for doing it. (But even when I was actually writing code full time some corners of the JS ecosystem seemed to lean too hard into the wild west mentality. Still do, I suspect, just now its Typescript in support of AI).

reply
Repeat after me: New! Fresh! Clean!
reply
Yeah that doesn't always work that well. Think you were lucky.

Add high DPI to the mix and things get rough very quickly. Also the common control have weird input issues (try ctrl+backspace in an Edit control). All those little things need to be fixed carefully for something to be ok in 2026.

reply
The one big challenge I've had with big legacy Win32/C++ codebases is migrating it fully from 32bit to 64bit. Loads of know-how and docs for complex GUI controls and structs are lost to time, or really fragmented. Other than that, yeah it really does all just work once you're past that.
reply
I went through that a few years ago and it actually went pretty smoothly. There were a few UINT_PTR or DWORD_PTR changes I had to get used to and a couple of string glitches (we mostly used the _T() macro for strings and already used the _t variants of string functions in the original code, so that helped).

The biggest problems were DAO (database) and a few COM controls that were not available in x64.

reply
Having to use macros for literal strings in your code is just incredibly stupid of Microsoft and/or C++.
reply
How do Linux and Java do it, when you want to compile your program in both 16-bit char and 8-bit char mode? Oh that's right, you don't.

You can pick one or the otherfor Windows too, so don't ask me why it's done that way. It was originally so you could compile for both the new hotness Unicode, and the old compatible ASCII.

reply
Partly because Microsoft resisted UTF-8 forever, and so using the ANSI/multibyte strings didn't therefore give you modern functionality. Why they didn't implement Unicode for Win95, I'm just not sure. If they had, the only reason to compile an ANSI version would have been to target Win32S (Windows 3.11).

Or, they could have implemented a UTF-8 code page for Win32 as soon as it was available and then most software could just use byte strings.

reply
Well it's still a 32 bit program so I guess that helps. Would probably require some porting to make it 64 bit native, but as long as you use the WPARAM, INT_PTR typed and what not correctly it 'should just work'.
reply
Yeah that's the bulk of the work for migrating small Win32 apps. Things escalate when someone has built their own dynamic GUI framework over Win32, used a range of GUI controls, and then built event-driven apps on top of that, it's a lot lol
reply
In 32-bit windows, you used to be able to see if a pointer was valid or not by seeing if it pointed to the last 2GB of address space. If it did, it was pointing to Kernel memory that was not valid for user mode code.

But then Large Address Aware (4GB limit) changes everything, and you can't do that anymore. In order for a program to be Large Address Aware, you need to not try to do things like check high bits of pointers, then every single library and DLL you use also needs to do the same.

reply
That sounds like the same ugly hack that caused programs not to be “32 bit clean” back in the day for Macs
reply
One difference is that the Mac OS itself was not initially 32-bit clean, with the top byte being used by the Memory Manager.
reply
Ah yes, these 68000 pointers have a spare 8 bits for me to use! Because nothing will ever need more than 16 MB of memory. Sigh.
reply
It's all good if you have 128kb ram but they should have had a plan to escape it from day one.
reply
This is how pointer authentication codes work on Arm64.
reply
Doesn't WINE have pretty decent documentation by now from all the reverse engineering?
reply
Win32 programming has been reduced to a small niche now. Even 20+ year old Win32 books don't cover things in-depth (or practical use cases) let alone the 32bit->64bit migration
reply
Wine cannot even install office 2014. It's not really as food as some claim sadly.
reply
Lutris can up to 2016.
reply
And the 12 different ways to define a string depending on which API you call
reply
I've not done MFC Win32 programming since 1999 but if I recall those programs don't execute the main() function. They instantiate the Win32 class for your app or something like that. I can't remember any details anymore.
reply
You still have a main function in Win32, it's just called WinMain and has a slightly different signature.

MFC has CWinApp, which you'd normally subclass, and a stock WinMain implementation that instantiates that, but it's not strictly necessary to subclass it, just convenient.

reply
But that’s the point the article’s making. At the C level you’ve got a fully functional system. Above that level (even at the C++ level), feature support is a mess.
reply
‘Madness is something rare in individuals — but in groups, parties, peoples, and ages, it is the rule’ —F. Nietzsche

(tongue in cheek)

reply
Winforms?

lol at them still bekng the best option. so much wasted effort trying to replace them

reply
Winforms is great until you try to make windows dynamically sized, or deal with DPI nicely. In every other regard it's still fine, and for accessibility actually _better_ than many subsequent frameworks. And produces nice small fast executables.
reply
I assume that if Microsoft hadn't abandoned WinForms for the next thing, it would support dynamic sizing and DPI properly. It's mindboggling how much time and effort they've wasted coming up with new GUI frameworks instead of just improving on what they have.
reply
It does, but many still think it is like using VB 6 and don't learn the additional APIs that provide that support, e.g. FlowLayoutPanel and TableLayoutPanel.

And for HiDPI, https://learn.microsoft.com/en-us/dotnet/desktop/winforms/hi...

reply
I don't think it's abandoned and it looks like there is a lot of activity around the high DPI concern.

https://github.com/dotnet/winforms/issues?q=is%3Aissue%20sta...

reply
I remember a marvelous quote from a guy that was at some MS conference and got handed a leaflet that said:

> WinForm or WPF, how to choose

and they were like: "the question I have isn't how to choose, but _why_ I have to choose".

reply
deleted
reply
Or, unless they've changed it, hardware accelerated rendering. Winforms was based on System.Drawing, which used GDI+, which was largely software rendering. This was confusing because GDI+ was not really related to GDI, which had and still does retain some hardware acceleration support. Even basic color fills start becoming an issue with a big window/monitor.

Winforms is also .NET based, so it's inaccessible if you don't want to write your UI in and take a dependency on .NET.

reply
transparency as well. WinForm really struggles with the idea of stacking elements on top of one another where there is an arbitrary amount of transparency or tricky shapes. Its just not worth the hassle compared to WPF.
reply
Windows dynamically sized is quite easy, people have had enough time to learn how to use layout managers in Windows Forms.

Naturally it is a bit more than just drag and drop controls from the toolbox.

HiDPI is supported in modern .NET, with additionally APIs, that aren't enabled by default only due to backwards compatibility.

reply
It's been a while since I've touched it, but IIRC they made WinForms play with Hi-DPI nicely.
reply
But isn't that illegal now? You have to write everything in rust according to their cto.
reply
How does it look? I mean, what do the widgets look like?
reply
This was an MFC project, so your old standard win32 common controls that looks the same since 98 or so.
reply
and it would work on linux with wine lol.
reply
Same here - our IOT device is a i5 running Windows IOT. Recently I switched from C++/Win32 to Golang and walk.
reply
Honestly, your GUIs are too simple to be part of this conversation. Try writing something like Spotify in WinAPI and that's not even a complicated GUI either.
reply
> Try writing something like Spotify in WinAPI and that's not even a complicated GUI either.

Fruityloops, now FL Studio, was written in Delphi and to my knowledge still is[1]. When ot launched there were no options but Win32 for Delphi.

That's just one example. Win32 makes it reasonably easy to skin things, and back in the 2000s a lit of programs did.

[1]: https://blogs.embarcadero.com/fl-studio-is-a-massively-popul...

reply
Spotify would be remarkably improved if it became a simple enough gui to be excluded from this conversation.
reply
WinAmp was the win32 music player of choice, once upon a time.
reply
Most apps at the time managed that quite successfully. IIRC Adobe Photoshop was an MFC app. There was no other API but Win32 API.
reply