Smalltalk and C fusion

More than three decades ago, Brad Cox and Tom Love took the mainstream and efficient C language and used Smalltalk’s object-oriented and messaging mechanisms to create an easy-to-use and lightweight extension to C. However, C and Smalltalk’s ideas and syntax were incompatible. For example, in Smalltalk everything is an object and all calls are messages:

233 log
Copy the code

Or use a factory method to instantiate an object:

p := Person name: 'sunnyxx' age: 26
Copy the code

At the time, an object-oriented C language was really attractive, but the message syntax had to be converted, so they developed a Preprocessor that parsed Smalltalk-style syntax, converted it into C code, and compiled it with other C code. The process is similar to CoffeeScript and JSX in JavaScript today, where you build a DSL and convert it into native language code using a converter.

It was a nice idea, but Smalltalk syntax was white space and colon, and if you had a complex nested call, it would be hard to parse, so they thought, Hey, don’t bother, put brackets around the message, it would be much easier to write it:

[Person name:"sunnyxx" age: 26];
Copy the code

This led to objective-C’s strange parenthesis, colon-like syntax. It was a temporary solution by all accounts, but it was probably the only solution at the time. It was much cheaper to borrow an existing C compiler than to build one, and it was fully compatible with C. With the boom of Apple’s development in recent years, Objective-C has become an increasingly uncomfortable place for Apple. First, Apple hated the addition of Objective-C support on GCC, rebuilt Clang by itself, and then reinvented Swift to completely replace it. It took 30 years to finally pay off the technical debt.

Well, with a Preprocessor, smalltalk-style code can only be analyzed and translated into C, and two problems need to be solved:

  1. C language to achieve an OOP object model
  2. Convert smalltalk-style Message mechanisms into C function calls

The object model is easy to design, just copy Smalltalk: Smalltalk concepts such as Class/Meta Class/Instance Method/Class Method, and keywords such as self/super/nil are Smalltalk. This conversion can be done in Preprocessing, because the rewritten Class is the original C Struct and needs to be set up according to the Smalltalk class-metaclass model without additional support.

Ps. IOS development exchange technology group: welcome to join, no matter you are big bull or small white are welcome to enter, share BAT, Ali interview questions, interview experience, discuss technology, we exchange learning and growth together!

Message mechanism is different, to implement a target (class/instance) to send a message name (selector) dynamically find the function implementation address (IMP) and call the process, It also needs to handle Message passing to its parent class, Message forwarding (Smalltalk called “message-not-understood”), etc. These behaviors cannot be implemented in Preprocessing or Build Time and need to be supported by several runtime C functions. All of these functions are bundled together to form the primitive Runtime.

So the original Objective-C = C + Preprocessor + Runtime

Note: GCC was originally used to support Objective-C with preprocessors, then as a compiler module, and later as a Clang implementation.

As a pure C extension, the Runtime implements only a few basic functions (such as objc_msgSend), but in order to build a whole set of objective-C object-oriented base libraries (such as Foundation), The Runtime also needs to provide a Root Class like NSObject as a starting point for object orientation, a Runtime reflection mechanism, and an API for Runtime modifications to the Class structure. Later, even as Objective-C itself continued to evolve, new language features were added, such as extensions to Clang and Runtime:

  • ARC: The compiler analyzes object references, inserts memory management functions where appropriate, and needs to package these functions into the Runtime, for exampleobjc_storeStrong.objc_storeWeakAnd so on, but also to deal with the dealloc function, automatically join the call to super, etc., seeThis article.
  • Lightweight Generics: Called “Lightweight Generics” because only compiler checking support is added and generic information does not affect the Runtime, so there is no need to change the Runtime library.
  • Boxed Expr (Sugars)@ 123), Array Literal (@ [...].), Dictionary Literal (@ {... }The same as lightweight generics, but with such as@ 123Rewrite into at compile time[NSNumber numberWithInt:123]You don’t have to change the Runtime.
  • Non Fragile Ivars: dynamic tuning of class instance variables, used to achieve Objective-C Binary compatibility. With The advent of Objective-C 2.0, the compiler and Runtime need to work together.

Therefore, the essence of Runtime is not the so-called “dark magic” Runtime API, or the various Swizzle methods you rarely encounter. It’s about learning how to deal with Type, Value, OOP data structures and message mechanisms, ABI design, etc. at the Objective-C level, and how to design such a small but beautiful C runtime extension. If I had to ask a Runtime question, it might be ** “Given C, how to implement an Objective-C?” **, go where you want to go.