6 ms·
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 impr
by robomartin 3y ago
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/sleFinal.pdf https://greenlab.di.uminho.pt/wp-content/uploads/2017/10/sle...
- galad87 3y agoThe 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 3y agoThe 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 3y agoIt’s actually dominated by the time complexity of the code running on it.
- bruce343434 3y agoAll things being equal, no. It's the language.
- saagarjha 3y agoAll things are never equal, so this isn’t particularly relevant or useful.
- bruce343434 3y agoThat philosophy isn't particularly relevant or useful. How else can you truthfully compare 2 things? Do you always pre-emptively give up and say "well things are always kind of different anyway so it doesn't matter how they compare"? PS, big O isn't everything. The constant factors that big O hides are in fact meaningful and can make or break an algorithm. Some languages make some constants worse by having extra overhead in some places or better when they have special facilities. See also: sorting algorithms deferring to insertion sort O(n²) for small runs, galactic algorithms. See also: languages where everything is a pointer to dynamic memory, vs languages that have actual values. The language default "dictionary" implementation and its time and space complexities. I could go on. For energy efficiency, or memory efficiency, or speed, choice of language does matter, and depending on the size and nature of the data, can overshadow algorithmic choices.
- saagarjha 3y agoI'm not saying those things don't matter, or that it's not possible that you can overcome some algorithmic complexity just by brute forcing it with a smaller constant. I'm saying that it is exceptionally rare that you are ever in a situation where you can go "oh I have these two identical pieces of software, let's just pick the one that uses the efficient language". Really, it comes down to this question: "this code is slow, what should I do to improve it?". The answer is usually "fix the time complexity somewhere or do less work" and it becomes good enough. Maybe in some isolated cases I might rewrite a bit of it in a different language if appropriate. When I say "time complexity dominates footprint" I mean that most of the code changes I make along the lines of changing something to take "100 ms → 2 ms" where the other language would be "25 ms → 0.5 ms" but you can see why I would not say that the language dominates here.
- saagarjha 3y agoObjective-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 3y agoThe 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 3y agoNeXTSTEP drivers were written in Objective-C.
- LispSporks22 3y ago> 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.
- speed_spread 3y agoFun C exercice: write a linked list impl that's guaranteed leak free, thread safe and type safe at compile time. Good luck!
- olliej 3y ago[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.
- spease 3y ago> 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. Like what? So far the discussion has revolved around rewriting a linked list, which people generally shouldn't ever need to do because it's included in the standard lib for most languages. And it's a decidedly nontrivial task to do as well as the standard lib when you don't sacrifice runtime overhead to be able to handwave object lifecycle management. - C++: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_list.h https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-... - Rust: https://doc.rust-lang.org/beta/src/alloc/collections/linked_list.rs.html https://doc.rust-lang.org/beta/src/alloc/collections/linked_... > No need to get defensive, no one is arguing that rust doesn’t do a lot of things well. That's literally what bsaul is arguing in another comment. :) > 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. Less perceived complexity. In Java and C# you're delegating the responsibility of lifecycle management to garbage collectors. For small to medium scale web apps, the added complexity will be under the hood and you won't have to worry about it. For extreme use cases, the behavior and overhead of the garbage collector does became relevant. If you factor in the code for the garbage collector that Java and C# depend on, the code complexity will tilt dramatically in favor of C++ or Rust. However, it's going to be non-idiomatic to rewrite a garbage collector in Java or C# like it is to rewrite a linked list in Rust. If we consider the languages as they're actually used, rather than an academic scenario which mostly crops up when people expect the language to behave like C or Java, the comparison is a lot more favorable than you're framing it as. > 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. You can certainly write a thread-safe linked list in C++, but then the enforcement of any assumptions you made about using it will be a manual burden on the user. This isn't just a design problem you can solve with more code - C++ is incapable of expressing the same restrictions as Rust, because doing so would break compatibility with C++ code and the language constructs needed to do so don't exist. So it's somewhat apples and oranges here. Yes, you may have provided your team with a linked list, but it will either (1) Perform less efficiently, due to needing the GC to check whether to free things (2) Require more expertise to use safely, due to C++ being incapable of expressing constraints > Rust has increased complexity of some “simpler” things to reduce the overall complexity of larger systems. This is an ok choice. This is sort of right and sort of not. In the context of Java and C#, Rust hasn't "increased complexity", it makes it explicit rather than paying runtime cost to try and hide it. In the context of C++, Rust hasn't "increased complexity" either, it makes it mandatory to deal with things that C++ lets slide. I'd look it more as Rust requires a higher degree of confidence in the code. Rust is more likely to take the programmer to task about "What did you mean?" or "Are you sure about that?". It's like doing a code review with an extremely pedantic developer. As a product of this, the performance is better because the programmer has pre-answered questions which would otherwise need to be disambiguated by a garbage collector at runtime. The less ambiguous behavior makes it faster to integrate modules, because the compiler can point out discrepancies between what the code owner said they expected and how something is being used by itself. But it's not like Rust added that complexity - it was always there. C++, C#, and Java just let you ignore at the risk of adversely affecting software stability or performance, respectively.
- deleted 3y ago[deleted]
- pjscott 3y agoObjC 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.)
- lyinsteve 3y agoThe Swift optimizer has matured dramatically since 2017, to the point where I think this benchmark would almost certainly not result in a 3x power usage/4x slowdown compared to C. On the current benchmark game, many of the purely algorithmic benchmarks are close to C performance, but many of these benchmarks seem to be stale and haven't been touched in quite a while. It would be nice if someone went through and rewrote these using current idiomatic Swift (where many of the "use unsafe bits for speed" tricks are unnecessary) and see how it really stacks up.
- robomartin 3y agoThat's good to know. I might have one of two projects in the next few months that will require jumping into Swift. Not touching Objective-C if I can help it.
- igouy 3y ago> It would be nice if someone went through and rewrote these using current idiomatic Swift It's always nice when someone else does what we can see is required, but mostly we have to be the ones to do that work.