[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)