[HN Gopher] Understanding Objective-C by transpiling it to C++
       ___________________________________________________________________
        
       Understanding Objective-C by transpiling it to C++
        
       Author : ingve
       Score  : 78 points
       Date   : 2023-12-02 14:45 UTC (8 hours ago)
        
 (HTM) web link (www.jviotti.com)
 (TXT) w3m dump (www.jviotti.com)
        
       | chrisbrandow wrote:
       | Nifty!
       | 
       | Of course, if one is interested in really understanding the nitty
       | gritty implementation of a lot of Objective-C (and UIKit
       | classes), then there is probably no better place to poke around
       | than Mike Ash's blog. He now works for Apple and hasn't posted
       | much since then, but the level of detail combined with the
       | clarity of his writing made it a go-to source for everyone in
       | early days of iOS development. It demonstrates why his getting
       | hired by Apple for systems/language engineering was highly
       | overdetermined.
       | 
       | https://www.mikeash.com/pyblog/
        
       | lloydatkinson wrote:
       | I know basically nothing about the Apple language ecosystem but
       | why does no one ever mention or seemingly use Objective C++?
       | 
       | Is it that Objective C is a better version of C with OO and C++
       | features?
       | 
       | If that's the case why was Objective C++ created?
        
         | filleokus wrote:
         | I've always understood Objective C++ to be a way to mix in C++
         | source code in an Objective-C code base, not really a new
         | language but more of a "mode" of linking / compiling.
         | 
         | > Objective-C++ does not add C++ features to Objective-C
         | classes, nor does it add Objective-C features to C++ classes.
         | For example, you cannot use Objective-C syntax to call a C++
         | object, you cannot add constructors or destructors to an
         | Objective-C object, and you cannot use the keywords this and
         | self interchangeably. The class hierarchies are separate; a C++
         | class cannot inherit from an Objective-C class, and an
         | Objective-C class cannot inherit from a C++ class. In addition,
         | multi-language exception handling is not supported
         | 
         | From a Stack Overflow comment / archived Apple docs:
         | https://stackoverflow.com/a/3684159
         | https://web.archive.org/web/20101203170217/http://developer....
        
           | jwells89 wrote:
           | Yes, in my experience the most common usages are to pair an
           | Objective-C Cocoa UI to cross platform C++ internals, to use
           | C++ for more performance critical parts of an app, or even to
           | just be able to take advantage of the plethora of C++
           | libraries without going all-in on C++.
           | 
           | Things might've changed with Swift being around now, but as I
           | understand one place where the Obj-C UI + C++ internals setup
           | used to be common was Audio Unit extensions due to the high
           | latency sensitivity of anything working with audio.
        
             | TillE wrote:
             | That first one is probably the most common, you'll see .mm
             | files for Apple-specific platform code in many big cross-
             | platform C++ projects.
        
         | dagmx wrote:
         | Objective C++ is just a way to mix C++ and Objective C code in
         | the same file. It's largely a convenience and not its own
         | language so to speak.
         | 
         | It's functionally the equivalent of how you can use C code
         | within C++ code, and a hint to the compiler to allow parsing of
         | C++ syntax as well as ObjC
        
         | saagarjha wrote:
         | It sees heavy use, most of it just isn't public. WebKit is, but
         | for example Facebook uses it for their apps.
        
         | jviotti wrote:
         | Author here. We do a LOT of Objective-C++ at Postman
         | (https://www.postman.com), as our upcoming desktop framework is
         | primarily C++.
        
         | olliej wrote:
         | Objective-c++ is used extensively, it's just not covered in
         | most discussions of objc because then you're having to explain
         | the exciting interaction between it objc object semantics and
         | C++'s. Eg the complexity skyrockets.
         | 
         | The biggest public user of it would likely be webkit, but
         | plenty of closed software both in and outside of apple use it.
         | 
         | But the reality is that it is at this point primarily a
         | bridging language. Post the introduction of ARC one of the
         | biggest win/reason to use it over raw objc went away.
         | 
         | But it's still tremendously valuable as a way to have a nice
         | API that is also ABI stable in a way that isn't the C and C++
         | misery pit. Of course now swift has the same ABI stability
         | support as well as a slew of other improvements so there seems
         | ever less reason to write new objc.
        
         | ksherlock wrote:
         | What's there to mention about it?
         | 
         | Long ago, c++ exceptions and objective C exceptions didn't play
         | well together but they've been unified so that's not an issue
         | anymore.
         | 
         | (In the beginning, Objective c exceptions were macros around
         | setjump()/longjump(). Objective C 2.0 added actual language
         | level support with @try/@catch/@finally/@throw which were
         | compatible with C++ exceptions)
        
           | astrange wrote:
           | You shouldn't use Objective-C exceptions though; most code
           | (and by default all ARC code) is not exception safe and will
           | leak memory if you jump through it.
        
         | flohofwoe wrote:
         | I bet there's a ton of Objective-C++ code around that serves as
         | a shim between a C++ codebase and macOS/iOS system frameworks.
         | The difference to plain ObjC isn't all that big except that the
         | "C part" uses C++ semantics (I guess that's why nobody
         | explicitly mentions it as ObjC++ but just files it under the
         | ObjC umbrella name)
        
       | mrpippy wrote:
       | I had no idea Clang had this rewriter, what an odd feature to
       | keep around for all these years.
       | 
       | I wonder if Apple actually uses/used it for anything.
        
         | saagarjha wrote:
         | It isn't really supported anymore so I don't think so.
        
         | zer0zzz wrote:
         | Windows iTunes if memory serves.
        
       | robomartin wrote:
       | Objective-C is interesting. The problem I had back when we were
       | using it was lack of performance. For us, in many cases,
       | refactoring code down to C easily improved performance over 400
       | times. Code that struggled to deliver output in a usable time
       | scale quickly became better than real time.
       | 
       | Today, in computing, we are using far more energy than necessary
       | because of the proliferation of inefficient languages in server,
       | desktop and mobile codebases. I would guess we could achieve a
       | non-trivial improvement in carbon footprint if computing were to
       | have the same kinds of energy efficiency requirements we impose
       | on appliances and vehicles.
       | 
       | This study [0], published in 2017, evaluated the time, energy and
       | memory efficiencies of some thirty languages. Sadly they did not
       | include Objective-C. Swift did make the list.
       | 
       | Table 4 shows the normalized results. C was most energy and time
       | efficient and very close (third) in memory efficiency. Swift
       | consumed nearly three times more energy, four times slower and
       | nearly three times the memory. Python requires 76 times more
       | energy, 72 times more time and three times more memory.
       | 
       | Clearly there is a cost to choosing a language along these
       | vectors. Given the ubiquity of computing in human life today, I
       | am sometimes surprised that we have not become far more critical
       | about permanently baking-in terribly bad energy inefficiency into
       | systems and products. Developing energy-efficient software using
       | languages like C, C++ and Rust isn't really that difficult.
       | 
       | [0] https://greenlab.di.uminho.pt/wp-
       | content/uploads/2017/10/sle...
        
         | galad87 wrote:
         | The object oriented part of Objective-C was never meant for
         | high performance code. Apple documentation always recommended
         | using C when performances are an issue, which can be easily
         | done because Objective-C is in fact C plus a bunch of object
         | oriented concepts.
         | 
         | However, in the end if you want every bit of performance you
         | have to use SIMD intrinsics or write asm directly, so even C
         | can be 8x times or more slower than a manually optimized code.
        
           | robomartin wrote:
           | The key point is:
           | 
           | As a percentage of the totality of software engineering,
           | virtually nobody looks at _energy_ optimization.
           | 
           | Smart phones? Well, the manufacturers likely pay attention to
           | this to some degree. However, I can guarantee you that almost
           | none of the millions of app developers working on third party
           | apps ever look at energy as an optimization vector.
           | 
           | That was my point, the carbon footprint of computing systems
           | is dominated --and permanently marked-- by the energy-
           | dominant language running on it.
        
             | saagarjha wrote:
             | It's actually dominated by the time complexity of the code
             | running on it.
        
               | bruce343434 wrote:
               | All things being equal, no. It's the language.
        
               | saagarjha wrote:
               | All things are never equal, so this isn't particularly
               | relevant or useful.
        
               | robomartin wrote:
               | > It's actually dominated by the time complexity of the
               | code running on it.
               | 
               | No. Please read the paper I posted. It's the language.
        
           | saagarjha wrote:
           | Objective-C isn't actually that bad as long as you're aware
           | of what constraints it puts on the compiler. People like to
           | go "oh method calls are so slow!" but you can do a billion of
           | them a second. The real performance win comes from selective
           | use of optimization-friendly code on hot paths that don't act
           | as a black box to the compiler. Some teams move at Lightspeed
           | to some weird janky architecture that just sucks in every
           | aspect because they think it will help, and it usually
           | doesn't.
        
             | meisel wrote:
             | The real slowdown of Objective-C method calls is at startup
             | where the caches haven't been filled. Pure Objective-C apps
             | typically spend 5-15% of startup time on objc_msgSend
        
           | pjmlp wrote:
           | NeXTSTEP drivers were written in Objective-C.
        
         | LispSporks22 wrote:
         | > Rust isn't really that difficult
         | 
         | Fun Rust novice exercise: Write a linked list implementation in
         | Rust.
         | 
         | Regarding the carbon footprint stuff, I think any runtime
         | performance efficiency stuff might often be outweighed but the
         | massive compile times for development and CI.
        
           | LeFantome wrote:
           | I am sure you know enough about Rust to know that writing a
           | linked list in Rust is not a "novice exercise". It is also
           | not something you require to use the language.
           | 
           | This is like a C# dev trolling a C developer by say "first
           | novice exercise", HTML encode a UTF8 string. I mean, it is a
           | single line of code in C# so how hard could it be in C?
           | 
           | Or, it is like a C dev telling a Java programmer that their
           | "first novice exercise" should be to write a fixed binary
           | layout to a device driver or even just to call directly into
           | an OS system call. Both are trivial in C after all. How about
           | using a hash table for something though? Reasonably big job
           | in C but new HashMap in Java.
           | 
           | Rust is designed to prevent exactly the kind of thing you do
           | to create a linked list and it is designed to make it
           | difficult for a good reason. It is a cherry picked example
           | meant to sound smart but, in reality, it is an eye-rollingly
           | dumb thing to say.
           | 
           | In DOS, I can write a program to dynamically overwrite and
           | extend the behaviour of the operating system in RAM. In
           | Linux, I cannot easily do that. I guess that means DOS is
           | more advanced? To me, this sounds like the argument you are
           | making about Rust.
           | 
           | I do it care which language people like. There are pros and
           | cons of each and legit arguments on use one over the other.
           | Why not use one of the valid arguments instead of dumb gotcha
           | comments that only tell us the languages are different and
           | not which one is better.
        
             | appleskeptic wrote:
             | > _This is like a C# dev trolling a C developer by say
             | "first novice exercise", HTML encode a UTF8 string. I mean,
             | it is a single line of code in C# so how hard could it be
             | in C?_
             | 
             | It's not like that at all. The difference you're
             | identifying is that C# has it in the standard library while
             | C does not. But it's a conceptually intricate problem and
             | implementing it from scratch in both C and C# would
             | actually be somewhat similar, but C# obviously has some
             | convenience features that would make the code tighter.
             | 
             | Linked lists are very simple and GP's complaint is that
             | Rust makes it very difficult to implement them.
        
               | LeFantome wrote:
               | The difference is that both C and C# let you use pointers
               | and make it your responsibility to use them correctly. C#
               | provides the facilities, both in the naked language and
               | in the standard library to not need pointers whereas you
               | need to use pointers to do even trivial tasks and so the
               | standard library makes extensive use of them. Pointers
               | are a core language feature of C so obviously it is
               | trivial to make use of them ( though not at all trivial
               | to use them safely ). Rust's core principle is that
               | unsafe memory access should be prevented at the language
               | level. Unsurprisingly, a data structure completely
               | reliant on potentially unsafe use of memory will be
               | difficult to implement.
               | 
               | Both C# and Rust include features in their standard
               | libraries so that implementing your own linked lists is
               | unnecessary precisely because you are not supposed to.
               | This is "non-idiomatic" as they say. C does not include
               | linked lists in the standard library because this is
               | exactly the kind of data structure you are meant to
               | create when needed as the language makes it completely
               | trivial to implement them. In C, a linked list is
               | completely idiomatic and many, many C projects use them.
               | 
               | If you write an OS in C, you will almost certainly create
               | a linked list structure. Linux did. If you write an OS in
               | Rust, you do not need to do that.
        
             | Kwpolska wrote:
             | Writing a linked list is a novice exercise in most
             | programming languages. It's also a novice exercise given in
             | first year of CS at universities. It might not be the most
             | efficient data structure, but it's a really trivial one.
        
               | pavlov wrote:
               | In assembly it's really easy to write self-modifying
               | code. It used to be the norm in fact. But today's high-
               | level programming languages generally make it impossible,
               | and most operating systems also prevent mutating code in
               | memory (no-execute page protection, etc.) Yet there are
               | still use cases like JIT compilers.
               | 
               | The linked list is the data structure equivalent of self-
               | modifying code. It's easy for a novice to understand, but
               | there's no great reason for anyone to actually do it
               | today outside of a specialized library.
        
             | bsaul wrote:
             | Your point would be valid if rust had code examples that
             | was actually simpler to write in rust than in other recent
             | languages.
             | 
             | My understanding is that rust provides safety guarantees
             | that no other language matches, but at the cost of pretty
             | much everything else. In that regard, the "linked list"
             | example is a pretty good (although maybe over-pathological)
             | example of the hard parts of the language.
        
           | speed_spread wrote:
           | Fun C exercice: write a linked list impl that's guaranteed
           | leak free, thread safe and type safe at compile time. Good
           | luck!
        
             | olliej wrote:
             | [edit: oliver used wall of text. Was it effective?]
             | 
             | No need to get defensive, no one is arguing that rust
             | doesn't do a lot of things well.
             | 
             | They're saying that a lot of the restrictions makes things
             | much harder than other languages. Hence the general problem
             | rust has where a lot of trivial tasks in other languages
             | are extremely challenging.
             | 
             | The fact that these things are much harder in rust due to
             | design decisions in the language to ensure that everything
             | is guaranteed to be safe in all cases does not change that
             | the language can be harder to use.
             | 
             | You're talking up getting a safe implementation in C, but
             | what matters is "can I get the same level of safety with
             | less complexity in any language", and the answer is yes:
             | Java and c# implementations of a thread safe linked list
             | are trivial. If I wanted I could do it in c++ though the
             | complexity would be more than c# and Java it would be
             | easier than rust.
             | 
             | We know that rust makes some things more complicated than
             | other languages for the same level of safety plans
             | correctness, but that's ok because complexity is a trade
             | off. Rust has increased complexity of some "simpler" things
             | to reduce the overall complexity of larger systems. This is
             | an ok choice.
             | 
             | But it is still a trade off, and part that trade off does
             | make some things harder.
             | 
             | People can point that out without it being an attack on the
             | language.
        
           | zozbot234 wrote:
           | You can do it safely by importing a ghost-cell crate. That
           | particular pattern is not yet part of the Rust standard
           | library because it comes in so many varieties, and it's not
           | yet clear how to best support it in the language. But I
           | assume it will get there at some point.
        
           | spease wrote:
           | > Fun Rust novice exercise: Write a linked list
           | implementation in Rust.                   struct LLItem<T> {
           | next: Option<Box<LLItem<T>>>,             value: T         }
        
         | pjscott wrote:
         | ObjC can be plenty fast, _if_ you know what you 're doing. And
         | there really isn't that much to learn; it's just that most
         | people _don 't_ learn and so they keep running into landmines.
         | I'll cover the main points right now, in no particular order.
         | 
         | 1. Allocation and deallocation involve calls to calloc/free,
         | which are rather costly. It's easy to accidentally create and
         | destroy an NSObject on each iteration of a hot loop. Be aware
         | that this comes with a performance hit, and can easily come to
         | dominate the time taken by that loop.
         | 
         | 2. Retains and releases are pretty fast, especially on Apple's
         | processors (which are optimized for non-contended atomic
         | operations). However, they _are_ atomic operations - some fancy
         | compare-and-swap thing usually - and so you should try to avoid
         | doing them on every iteration of a hot loop.
         | 
         | 3. ObjC method calls are slower than C++ vtable dispatch, which
         | in turn is slower than static function calls. Also, there's no
         | inlining opportunity. There _is_ caching to make method calls
         | faster if you call the same method a lot, and the code for
         | cache lookups is impressively fast, but if you need some code
         | to be Fast, consider using C-style functions in critical parts.
         | 
         | 4. When in doubt, use the Instruments profiler to find
         | bottlenecks. It's really good.
         | 
         | And now a small grab-bag of more minor ones:
         | 
         | 5. +[NSString stringWithFormat:] is surprisingly slow, or it
         | was when last I checked. Its CoreFoundation counterpart is
         | similarly slow. (It's the same underlying code.)
         | 
         | 6. When you load a plist, most of which will be deallocated
         | almost immediately, surrounding this with an @autoreleasepool
         | block often does wonders to reduce heap fragmentation. Same
         | goes for other operations which will tend to produce large
         | memory spikes of objects that will stay allocated pending an
         | autorelease pop.
         | 
         | 7. The Accelerate framework defines a number of SIMD data
         | types; e.g. simd_float8 is a vector of 8 single-precision
         | floats. You can do arithmetic on them like a normal numeric
         | data type, and the compiler will automatically emit cross-
         | platform SIMD code. If your needs are fairly basic, this is a
         | remarkably easy way to do SIMD programming. I've managed to get
         | ~8x speedups with it before. (A pity that the docs are so
         | lacking.)
        
       | VancouverMan wrote:
       | Portable Object Compiler may be of interest, too.
       | 
       | It's an open source compiler for a more traditional dialect of
       | Objective-C, and it generates C code:
       | 
       | https://sourceforge.net/projects/objc/
       | 
       | The bootstrap source release of Portable Object Compiler itself
       | shows the kind of C code the compiler generates from Objective-C:
       | 
       | https://sourceforge.net/projects/objc/files/bootstrap/
        
       | Rexxar wrote:
       | I have started to do the same thing with go but it's largely
       | unfinished. The next thing I will try to do when I have some time
       | is to implement goroutine with the new c++20 coroutines.
       | 
       | (https://github.com/Rokhan/gocpp)
        
       | deviantbit wrote:
       | I loved Objective-C when I was developing on the NeXT. I haven't
       | done with it much since then. I don't think it really got the
       | credit it deserved. Templates would have been nice to have with
       | it. Messages where so useful.
        
       | Towaway69 wrote:
       | Slightly off topic but did anyone ever use Objective-J[0],
       | specifically Cappuccino which was a great framework for building
       | JS frontends.
       | 
       | I built an application using Cappuccino after having built a
       | bunch of apps for iPhone and it was the most intuitive framework
       | after getting involved in Xcode and Co.
       | 
       | Is cappuccino still a thing since Apple went to swift?
       | 
       | [0] https://www.cappuccino.dev/learn/objective-j.html
        
         | JimRoepcke wrote:
         | I built an app using Cappuccino and Objective-J back around
         | 2010.
         | 
         | We even built an EOF/CoreData clone on top of it. Good times.
         | 
         | It was incredible to work with, but ultimately not very
         | "webby".
         | 
         | I'd rather have WebObjects back. It should have never died.
        
           | Towaway69 wrote:
           | Looking back it's amazing how much effort the authors made to
           | make it objective-C like and not at all like any other Web
           | technology.
           | 
           | I guess that made it too niche for a broader audience.
        
             | dottrap wrote:
             | I saw a few presentations from the 280 North guys. It was
             | clearly impressive what these 3 guys built. Learning from
             | Cocoa/Objective-C/Interface Builder well, they realized
             | they needed to build 3 separate, but interconnected things,
             | the framework (Cappuccino), the language (Objective-J), and
             | the GUI builder (Atlas).
             | 
             | They sold to Motorola for $20 million in 2010, and that was
             | the kind of the last I heard.
             | 
             | https://news.ycombinator.com/item?id=1631002
        
       | zer0zzz wrote:
       | I'm not sure if the authors comment that the rewriter isn't used
       | is accurate.
       | 
       | It might have been used for the windows port of iTunes.
        
       | _3u10 wrote:
       | It's mostly just objc_msg_send and a couple other methods in that
       | header.
        
       | k4st wrote:
       | Cool! You might even be able to run Rellic [1,2] on the LLVM IR
       | produced by Clang when compiling Objective-C code. If it works,
       | this will spit out goto-free C code, not C++.
       | 
       | [1] https://github.com/lifting-bits/rellic
       | 
       | [2] https://blog.trailofbits.com/2022/05/17/interactive-
       | decompil...
        
       ___________________________________________________________________
       (page generated 2023-12-02 23:00 UTC)