50 comments

[ 4.2 ms ] story [ 76.5 ms ] thread
Good time to check out ObjFW [1], it's a cross platform ObjC framework that's just really awesome

[1] https://git.nil.im/ObjFW/ObjFW

I hadn't come across this. Insane (if true, I've never tried) that GnuStep is not 100% compatible, surely that would be the point.

How easy is it to port, say, a Leopard-era Objective C app to ObjFW?

I tried this with an old iOS only game a few years ago. It is clearly not a heavily used library, but it seemed to work ok

- There was a bug or two I had to patch, but the code is readable, so it wasn't a big deal

- OFString, etc aren't intended to be 1:1 replacements for NSString, etc. This wasn't a real problem. They mostly match, and all I needed to do was write a few categories

- The runtime functions are not compatible at all, but most projects wouldn't touch those

- CoreFoundation and the other C APIs are not there at all, so you'll need replacements

- It is a replacement for Foundation framework, not AppKit, so if it is a GUI app you still have a lot of work to do

It really is really awesome! It's what I write in when I want to use it on Linux.

GNUStep is stuck in 1995 sadly.

I really miss Objective-C, and in the world of Swift craziness [1] I'm reminded often of this blog post [2] wondering what would have happened if Apple hadn't encountered Second System Syndrome for its recommended language.

(There's a decent argument it encountered it in iOS and macOS too.)

[1] https://github.com/swiftlang/swift-evolution/blob/main/propo... -- apologies to the authors, but even as a previous C++ guy, my brain twisted at that. Inside Swift is a slim language waiting to get out... and that slim language is just a safer Objective C.

[2] https://medium.com/goodones/pareto-optimal-apple-devtools-b4...

> Inside Swift is a slim language waiting to get out... and that slim language is just a safer Objective C.

Rust? Rust is basically a simpler Swift. The objective-c bindings are really nice too, and when you're working with obj-c you don't have have worry about lifetimes too much, because you can lean on the objective-c runtime's reference counting.

I think the way to think about it is that with Rust, it's as if all the goodness in Swift was implemented with in the "C" level, and the Objective-C but is still just library-level a runtime layer on top. Whereas Swift brings it's own runtime which greatly complicates things.

>[1] https://github.com/swiftlang/swift-evolution/blob/main/propo... -- apologies to the authors, but even as a previous C++ guy, my brain twisted at that. Inside Swift is a slim language waiting to get out... and that slim language is just a safer Objective C.

These kinds of features are not intended for use in daily application development. They're systems-language features designed for building high performance, safe, very-low-level code. It will be entirely optional for the average Swift developer to learn how to use these features, just in the same way that it's optional for someone to learn Rust.

I don't miss @ and [] all over the place, even if Objective-C has some cool ideas into it.

I do agree Swift's design has gone a bit overbord, we wanted Delphi and got Haskell instead.

However note the same phenomen happening with other languages, as soon as you have a team being paid to develop a language, their job depends on adding features in every single release.

Programming languages are products, even those that praise C's simplicity have certainly not read compiler manuals about language extensions, or the mailings from WG14 proposals.

> we wanted Delphi and got Haskell instead

Please elaborate.

> However note the same phenomen happening with other languages, as soon as you have a team being paid to develop a language, their job depends on adding features in every single release.

Users also request those features. You said yourself that programming languages are products. In that sense, people are always evaluating them through the lenses of utility (the economics concept), and if they have to pick between two languages, with similar capabilities, they will pick up the one that maximises that utility.

This to weird design decisions getting inserted into the fabric as a consequence (the current state of C++ comes to mind). And given developers are too opinionated about everything, we get politics as a side effect.

I never have to miss Objective-C because I still write in it! I never hopped on the Swift train because I saw it as an inferior language to Objective-C. And a decade later I'm more sure of that. It's such a joy to still write in an amazing language. Yes I use Python too and that is a joy. But nothing like Objective-C.
I still find Objective-C++ useful for writing MacOS apps that make heavy use of C++ libraries (e.g.; Eigen, OpenCV). The caveat is I have done a lot of Objective-C programming and Swift is still not as seamless as I would like bridging with modern C++ and the the STL.
Obj-C++ was used for some hall-of-fame OS X apps, e.g. TextMate
I made some camera and GPU-heavy features in the Facebook and Instagram app in ObjC++, and yes, it was nice to have that impedance match.

I don't work there anymore, I wonder if they're using the C++ - Swift interop that now exists.

> [[those squareBrackets] lookInsane:YES].

Nah, they are perfectly sane. They look like little ASCII envelopes because that's exactly the metaphor. Square brackets send messages.

At this point in my career, I can't go back to a language that doesn't have support for Optionals or compiler validation of nullable types. I can sacrifice async or fancy stream apis, but I will never go back to chasing null pointer exceptions on a daily basis.
If you use Objective-C objects, operations on null pointers are just a no-op, so there is not such thing as chasing exceptions.
Objective-C did not have null pointer exceptions, though some libraries added them.
When Swift 1 came out, I was migrating an ObjC app that used CoreData to it and found a bug where nullable cols in the CoreData schema got non-nullable properties in the autogenerated Swift. Found out when I had a non-nullable property actually get set to null at runtime, and the compiler wouldn't let me add a check that it's null.
I bounced off of Objective-C not because of its message-passing OO. That was the actual cool part. I bounced off because of the insane amount of boilerplate prototyping and headers required to use it.

I think every OO language should be using Smalltalk's message-passing style rather than holding hard references, and Objective-C is a great model. But discard the rest.

> you’ll realize how small a language it is, how easy to hold in your palm and turn around and understand all sides of it

I have never programmed in ObjC but was curious to learn how it works, and so I decided to write a ObjC runtime [0]. It took less than 2000 lines, and a large number of them are comments. Now I wonder how easy would it be to do dome lispy symbolic computing in it. Maybe something like a Prolog.

[0] https://gist.github.com/namandixit/76cd084676acdf16cfd014cbb...

I recently started writing for macOS in Swift and, holy hell, the debuggability of the windowing toolkits is actually unparalleled. I've never seen something that is this introspectable at runtime, easy to decompile and analyze, intercept and modify, etc. Everything is so modular, with subclassing and delegation patterns everywhere. It seems all because of the Objective-C runtime, as without it you'd end up needing something similar anyway.

You can reach into built-in components and precisely modify just what you want while keeping everything else platform-native and without having to reimplement everything. I've never seen anything like this before, anywhere. Maybe OLE on Windows wanted to be this (I've seen similar capabilities in REALLY OLD software written around OLE!) but the entirety of Windows' interface and shell and user experience was never unified on OLE so its use was always limited to something akin to a plugin layer. (In WordPad, for example)

The only thing that even seems reminiscent is maybe Android Studio, and maybe some "cross-platform" toolkits that are comparatively incredibly immature in other areas. But Android Studio is so largely intolerable that I was never able to dig very far into its debugging capabilities.

I feel like I must be in some sort of honeymoon phase but I 100% completely understand now why many Mac-native apps are Mac-native. I tried to write a WinUI3 app a year or two ago and it was a terrible experience. I tried to get into Android app development some years ago and it was a terrible experience. Writing GUIs for the Linux desktop is also a terrible experience. But macOS? I feel like I want to sleep with it, and I weep for what they've done with liquid glass. I want the perfection that led to Cocoa and all its abstractions. Reading all the really, super old documentation that explains entire subsystems in amazingly technical depth makes me want to SCREAM at how undocumented, unpolished and buggy some of the newer features have gotten.

I've never seen documentation anything like that before, except for Linux, on Raymond Chen's blog, and some reverse-engineering writeups. I do love Linux but its userspace ecosystem just is not for me.

Maybe this is also why Smalltalk fiends are such fans. I should really get into that sometime. Maybe Lisp too.

> Writing GUIs for the Linux desktop is also a terrible experience.

I've found the DX for GTK to be at least tolerable. Not fantastic, but I can at least look at a particular API, guess how the C-based GObject code gets translated by my language bindings of choice, and be correct more often than not. The documentation ranges from serviceable to incomplete, but I can at least find enough discussion online about it to get it to do what I want.

Also, GTK apparently ships with a built-in inspector tool now. Ctrl-Shift-I in basically any GTK app opens it. That alone is extremely useful, and you basically have to do nothing to get it. It's free.

I've never tried Qt. The applications that use it always seem off to me.

As for OLE, you're actually thinking of COM, not OLE. They were co-developed together: COM is a cross-language object system (like GObject), while OLE is a set of COM interfaces for embedding documents in other arbitrary documents. Like, if you want to put a spreadsheet into a Word document, OLE is the way you have to do that. Microsoft even built much of IE[0] on top of OLE to serve as its extension mechanism.

OLE is dead because its use case died. Compound documents as a concept don't really work in the modern era where everything is same-origin or container sandboxed. But COM is still alive and well. It's the glue that holds Windows together - even the Windows desktop shell. All the extension interfaces are just COM. The only difference is that now they started packaging COM objects and interfaces inside of .NET assemblies and calling it "WinRT". But it's the same underlying classes. If you use, say, the Rust windows crate, you're installing a bunch of language bindings built from WinRT metadata that, among other things, call into COM classes that have been there for decades.

Mac apps are Mac native because Apple gives enough of a shit about being visually consistent that anyone using a cross-platform widget toolkit is going to look out of place. Windows abandoned the concept of a unified visual identity when Windows 8 decided to introduce an entirely new visual design built around an entirely new[1] widget toolkit, with no consideration of how you'd apply any of that to apps using USER.dll/Common Controls. As it stands today, Windows does not have a good answer to "what widget toolkit do I use to write my app", and even Microsoft's own software teams either write their own toolkits or just use Electron.

[0] Petition to rename ActiveX to WebOLE

[1] OK, yes, XAML existed in the Vista era, but that was .NET only, and XAML apps didn't look meaningfully different from ones building their own USER.dll window classes like it's 1993.

Writing objective-c code for mac os GUI apps was one of those things that finally made "interfaces"/"protocols" really click for me as a young developer. Just implement (some, not even all) method in "FooWidgetDelegate", and wire your delegate implementation into the existing widget. `willFrobulateTheBar` in your delegate is called just before a thing happens in the UI and you can usually interfere or modify with the behavior before the UI does it. Then `didFrobulateTheBar` is called after with the old and new values or whatever other context makes sense and you can hook in here for doing other updates in response to the UI getting an update. If you don't implement a protocol method, the default behavior happens, and preserving the default behavior is baked into the process, so you don't have to re-implement the whole widget's behavior just to modify part of it.

It's probably one of the better UI frameworks I think I've used (though admittedly a lot of that also is in part due to "InterfaceBuilder" magic and auto-wiring. Still I often wish for that sort of elegant "billions of hooks, but you only have to care about the ones you want to touch" experience when I've had to use other UI libraries.

  > I feel like I must be in some sort of honeymoon phase but I 100% completely understand now why many Mac-native apps are Mac-native.
it seems like everybody prefers ios, but i really still think after all these years i prefer appkit; it really is so well documented and the quality of the api is the best i've seen by a long mile
Welcome to Smalltalk, Lisp, Java and .NET, which alongside NeXTSTEP/OS X, share a common linage of tooling ideas, and programming language features.

Hence why given the option I rather stay in such environments.

Now Android Studio is the product of Google's mess, and I am glad to have moved away from Android development, it also doesn't have anything to do with enjoying pure Java development on desktop (Swing, SWT, JavaFX) and server.

> Reading all the really, super old documentation that explains entire subsystems in amazingly technical depth

Any links?

> Maybe this is also why Smalltalk fiends are such fans.

I started getting interested in Smalltalk after I tried writing a MacOS program by calling the Objective-C runtime from Rust and had a surprisingly good time. A Smalltalk-style OO language feels like a better base layer for apps than C.

That's it, I'm pivoting my startup technically and rewriting everything in ObjC! /s
I wonder how well AI generates Obj-C - it might well produce better quality code for your token/buck!

In a previous life, one would select the programming language according how expensive developers were. Nowadays it's the quality that an AI can generate. What a wonderful future we've put together. /s

I've always liked Objective-C. Despite me not really liking object-oriented programming, I appreciate that its one of a handful of languages to do actual smalltalk-esque oop
I really enjoyed Obj-C when I did some iOS work back in 2015/2016. It was my first non-JS language, and it taught me so much that I didn't understand since I started out doing web dev.
Smalltalk is like pizza. Even when it's bad, it's still pretty good.
IMHO the one great feature of Objective-C (compared to C++) is that it doesn't interfere with any C language features. In C++ the C 'subset' is stuck in the mid-1990s, while Objective-C "just works" with any recent C standard.
Interestingly, I recently auto-translated wget from C to a memory-safe subset of C++ [1], which involves the intermediate step of auto-converting from C to the subset of C that will also compile under clang++. You end up with a bunch of clang++ warnings about various things being C11 extensions and not ISO C++ compliant, but it does compile.

[1] https://duneroadrunner.github.io/scpp_articles/PoC_autotrans...

I think C++ have caught up with C99 already. So it's late 90s, not mid-90s :)
What C features can you not realistically use from C++?
The one really funny feature of Objective-C++ is that it lets you write C++ using modern C features that haven't been pulled into C++, and you don't have to actually use the Objective part. Designated initializers before C++ got them were the main actually useful application of this.
Every so often I get weirdly obsessed with Objective-J, which "has the same relationship to JavaScript as Objective-C has to C". It is (was?) an absolutely bonkers project. I think it has more or less died since 280 North was acquired.

https://www.cappuccino.dev/learn/objective-j.html

Wow, I haven't written any Objective-C since around 2012. I just went back and looked at some code I had written back then and that really brought back some memories. I was much happier then. I'm perpetually sad and unemployed now.

That's all. Enjoy yourselves.

One of the things I miss about Objective C is just how easy it is to call into a C API, or otherwise include a C function if that's the easiest way to call into a C API.

I shipped a cross-platform C# project, and once I realized I could expose "ordinary C" from the Objective C part, it was very easy to integrate the two without using a framework. (It helped that the UI was 100% Objective C, so there wasn't much surface area between the C# and Objective C parts. We initially used MonobjC, but first I had to work around a shortcoming, and then we needed to remove MonobjC due to licensing and some of the newer C# integration layers were not available.)

The most difficult part of Objective-C is its ARC rules, and mixing ARC and non-ARC code in the same project.
Any popular cross-platform GUI toolkits? How do you find GNUstep?
I do not get this argument at all. A long time ago I ported a simple sudoku solver to Objective-C by using the foundation classes, like NSMutableArray. It was terribly slow. All those messaging sending just to do what should have been a single instruction (or less!) That’s when I realized that if you want speed in an Objective-C app, you really are going to reach for the C subset. The objective part is really good for building GUIs, but not for pure computation.
I still love Objective-C and you can pry it from my cold dead hands - tho I basically just call in to it from Rust these days for convenience reasons (cargo).

That aside, I was glancing through the source code for the engine and noticed this:

https://codeberg.org/brentsimmons/SalmonBay/src/branch/main/...

I wonder why they opted to do this instead of NSJSONSerialization - maybe I'm just misunderstanding the use for the class tho.

libobjc is simply great. Old school, but great.