Ask HN: Why isn't native mobile libraries written in C?

2 points by Svenskunganka ↗ HN
I've always wondered why Apple and Google decided to use Objective-C/Swift/Java for their native iOS/Android libraries instead of plain C. Considering you can write bindings to C in virtually every programming language out there whether the programming model differs a lot or not (e.g OO or functional), you would be able to create mobile apps in any language you want if it can target the architecture.

Is there any particular reason why Google and Apple didn't take this approach? Does it introduce problems with the permission systems for apps? Security issues?

9 comments

[ 4.0 ms ] story [ 38.3 ms ] thread
Firstly, C kinda sucks. Undefined behaviour is unavoidable, and compilers see it as license to do whatever they please, so you can actually get a segfault because the compiler decided to "optimize" away your null pointer checks. C is also dangerous, and Apple and Google don't want users getting segfaults. And even if the plan was to bind the C apis to high level languages, people would just write their apps in C.

Secondly, for stateful graphics programming, the most common kind of application on mobile, OO works really well. So Apple and Google both picked languages that support OO.

Finally, despite all this, both Apple and Google have native C apis. You can write C freely in Objective-C, which is a superset, and Android has its NDK.

Compiler dev here : "and compilers see it as license to do whatever they please", isn't that the definition of undefined behavior?
Well, yes. That's why compilers can comply to the spec and do that. But nobody EVER writes any C with no UB, so there are no guarantees about how the compiler will compile it. Most C programmers, I would guess, do not know the entire list of UB. The end result is that you can write code that looks completely safe to most, but compiles without any checks.
(comment deleted)
My #1 complaint about C is the .so file doesn't contain enough metadata to introspect functions and fields enough to use them metaprogramatically without also looking at the .h file; you can get the address with a symbol but that is not complete.

Compare that to Java where you can look at the class file and get enough metadata to do anything.

While interopability is important in the desktop and server space, and for legacy systems, I am not 100% convinced that for a new and highly curated/guarded platform like android/iOS it matters that much. Google/Apple expect most people to develop using the platform canonical language.

Also while C has great interop. it still comes at a cost, you loose a lot of modern programming constructs like exception, static initialization, reflection and garbage collections.

It takes way too much of time to code, its complex, then there is porting and mainly there is no need to use C with kind of mobile specifications we've these days. These phones are faster than computers 15 years ago.

I have been part of teams where entire stack (even UI layer) was in C. malloc() was a prohibited function by design! It was way too much of code for what could be accomplished by having c++-STL these days. But then the system specifications were very low (~130 Mhz) too.

In one of embedded projects couple of years earlier - the trade off discussion we had was whether to include boost or to have a JVM ported to it! So we 've come far away.

With good chances of myself corrected here - I 've a feeling that C will be restricted to drivers/kernel, in most systems going ahead, as everything that can be written in C in rest of layers can be written in OO languages.

eg: OS based on nodejs on top of linux-kernel: https://node-os.com/

Can you elaborate on why malloc() was prohibited?
Designing of component also involved a meticulous way of finding how much memory would be used. Most of the memory used was in stack and bss - to maintain model-and-state-machines. Predominantly these were 'static' variables. Then any allocation on heap was done using local-heap manager functions. Local-heap-manager allocated buffer of 3 or 4 sizes usually in terms of large kilo bytes - this was usually to process audio/video/image(AVI) frames. These allocation were mainly called by components involved in AVI libs. And any call to local-heap-manager had to get some sort of approval at architecture level - most of the time if it was not for AVI - it would be turned down with plenty of debate. This local-heap-manager abstracted to sort of a pipeline at system level. Only one pipeline can be active at any given state. Switch of pipeline meant - release-allocation of these large chunks of memory. Each pipeline involving say x components would use highest possible memory of say y. The error that was usually frowned upon was 'low memory' of system - this usually occured when a hardware unit was slow to process say a block of AVI. Also the total cpu load of each pipeline was also monitored.