Live data from Hacker News

The Objective-C Runtime and Swift Dynamism

academy.realm.io

21–30 of 41 posts

Re: The Objective-C Runtime and Swift Dynamism

#21
post #9

Earlier quoted context omitted.

I think it means "dynamic," in the sense that when you call a method, the object's class is looked up and the class's method list is looked up and the methods' implementations are looked up and the class is even given a chance to handle the lookup itself. It doesn't just support reflection, it reflects pervasively. This basically corresponds to what we usually mean when we say a "dynamic language."

Is that lookup done all the time (for each invocation of the same method):? Or is it done at a single point in time, like a JIT, but after that the method is “fixed”? With the possibility to intercept/replace code at runtime (at any time, not just at a resolve/jit stage) it must be very hard for the runtime to optimize calls (i.e make direct calls instead of indirect via method pointer lookup)? I’m not familiar with…

Conceptually for every call. In practice, a language can do less, as long as it always calls the correct method.

How exactly it finds that method is an implementation detail, but fast implementations will cache the results of method lookups. For example, https://developer.apple.com/library/content/documentation/Co... states:

”To speed the messaging process, the runtime system caches the selectors and addresses of methods as they are used. There’s a separate cache for each class, and it can contain selectors for inherited methods as well as for methods defined in the class. Before searching the dispatch tables, the messaging routine first checks the cache of the receiving object’s class (on the theory that a method that was used once may likely be used again). If the method selector is in the cache, messaging is only slightly slower than a function call. Once a program has been running long enough to “warm up” its caches, almost all the messages it sends find a cached method. Caches grow dynamically to accommodate new messages as the program runs.”

Re: The Objective-C Runtime and Swift Dynamism

#22
post #9

Earlier quoted context omitted.

I think it means "dynamic," in the sense that when you call a method, the object's class is looked up and the class's method list is looked up and the methods' implementations are looked up and the class is even given a chance to handle the lookup itself. It doesn't just support reflection, it reflects pervasively. This basically corresponds to what we usually mean when we say a "dynamic language."

So more or less dynamic dispatch then?

Yes, a "dynamic language" is generally one where all method calls are dynamically dispatched. They're usually implemented using "message-passing" terminology (ex. "send" in Ruby, "objc_msgSend" in Objective-C) as a throwback to Smalltalk, which inherited the terminology from Actor systems even though the semantics differ substantially.

Re: The Objective-C Runtime and Swift Dynamism

#23
post #9

Earlier quoted context omitted.

I think it means "dynamic," in the sense that when you call a method, the object's class is looked up and the class's method list is looked up and the methods' implementations are looked up and the class is even given a chance to handle the lookup itself. It doesn't just support reflection, it reflects pervasively. This basically corresponds to what we usually mean when we say a "dynamic language."

Is that lookup done all the time (for each invocation of the same method):? Or is it done at a single point in time, like a JIT, but after that the method is “fixed”? With the possibility to intercept/replace code at runtime (at any time, not just at a resolve/jit stage) it must be very hard for the runtime to optimize calls (i.e make direct calls instead of indirect via method pointer lookup)? I’m not familiar with…

Many languages use "inline method caching" - that is, a "call_dynamic x_named_method" bytecode is replaced with a "guard_and_call_static 0xfffffff" once the callsite is evaluated. In some languages invalidating this cache by calling a method with polymorphic arguments or altering the receiving class can be extremely expensive, so there are usually second-order optimizations applied.

Objective-C: Takes one method pointer indirection / jmp trampoline forever, but caches "selectors" on the class so that they become a simple lookup rather than a full evaluation. See sibling comments for better write-ups than I could find.

Most JS runtimes: Trace JITs mean many method invocations are compiled into traces and become either inline instructions or native function calls. Also uses "hidden classes" to implement inline method caching, where the callsite is replaced with the specific address of the call once the dispatch is resolved. https://github.com/sq/JSIL/wiki/Optimizing-dynamic-JavaScrip... , https://blog.ghaiklor.com/optimizations-tricks-in-v8-d284b6c...

Ruby: Also uses inline method caching - when a method is resolved that callsite is replaced with a jump straight to the resolved method in the bytecode. Invalidation used to occur any time a class was modified in any way but has been made more specific over time: https://github.com/charliesome/charlie.bz/blob/master/posts/...

Re: The Objective-C Runtime and Swift Dynamism

#24
post #8

>"Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, ..." I had not heard the term "runtime-oriented language" before. Is this really just another term for "supports reflection"? If not what would be other examples of "runtime-oriented" languages?

I think the author means "late binding" - the method lookup is done at invocation time rather than compile time. (There is caching, etc, to make it fast.)

Re: The Objective-C Runtime and Swift Dynamism

#25
> Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, and this gives you great flexibility because you can change those links. The alternative, where Swift is most of the time, is compiletime-oriented languages. So in Swift everything is a bit more harder bound, and you get more safety, but it’s less flexible.

> This is what this debate was all about.

Not just safety, but also performance. Swift offers significant performance gains when you don’t need the dynamism. Swift lets you opt into dynamic features (as he later explains), and you can seemlessly interact with Objective C on Mac platforms. But you don’t have to pay the penalty for dynamism in the vast majority of your code that doesn’t use these features.

Edited: I also pointed out some additional mistakes in the post, but removed that because this comment got too long.

Re: The Objective-C Runtime and Swift Dynamism

#26
post #25

> Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, and this gives you great flexibility because you can change those links. The alternative, where Swift is most of the time, is compiletime-oriented languages. So in Swift everything is a bit more ha…

> Not just safety, but also performance. Swift offers significant performance gains

This is a common misconception. It is not true. Swift is slower than Objective-C, typically significantly so.

Re: The Objective-C Runtime and Swift Dynamism

#27
post #25

> Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, and this gives you great flexibility because you can change those links. The alternative, where Swift is most of the time, is compiletime-oriented languages. So in Swift everything is a bit more ha…

> Not just safety, but also performance. Swift offers significant performance gains This is a common misconception. It is not true. Swift is slower than Objective-C, typically significantly so.

When arguing against a “common misconception,” one typically provides a source.

You seem to be saying that Apple’s claims are not only wrong, but ObjC is somehow faster despite having to do more work. Swift has no runtime method table lookups, no extra objc_msgSend calls, better ability to analyze and inline code, no retain/release dance for code with value semantics, etc. Every benchmark I’ve seen shows Swift faster for these reasons.

Re: The Objective-C Runtime and Swift Dynamism

#28
post #25

> Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, and this gives you great flexibility because you can change those links. The alternative, where Swift is most of the time, is compiletime-oriented languages. So in Swift everything is a bit more ha…

Tooling and maturity are reasons why not currently, maybe give it a couple of years ;)

Debuggers can not work properly, xcode indexing can beachball, compile times are quite a bit longer, there is API churn from version to version, a lack of ABI stability forcing you to bundle swift with your app increasing binary size and other bugs.

Re: The Objective-C Runtime and Swift Dynamism

#29
post #25

> Before we start, Objective-C is a runtime-oriented language, which means that all of the links between your methods and variables and classes are deferred to the last moment possible to when your app is actually running, and this gives you great flexibility because you can change those links. The alternative, where Swift is most of the time, is compiletime-oriented languages. So in Swift everything is a bit more ha…

> Not just safety, but also performance. Swift offers significant performance gains This is a common misconception. It is not true. Swift is slower than Objective-C, typically significantly so.

I can't speak for other people's code, but I regularly profile and read the machine code generated by the Swift compiler, at least for my hot loops. If you know what you are doing (use the right annotations and optimizer flags), even fairly generic code often compiles down to something that comes very close to what an optimizing C compiler would generate. Sometimes it generates even faster code, because the Swift calling convention can make better use of available registers. Sure, there are situations where it generates less optimal code, but generally generic idiomatic Swift is on a different level than a (non-profiling) compiler for idiomatic Objective-C can ever come close to. That's my experience.

Re: The Objective-C Runtime and Swift Dynamism

#30
post #27

Earlier quoted context omitted.

> Not just safety, but also performance. Swift offers significant performance gains This is a common misconception. It is not true. Swift is slower than Objective-C, typically significantly so.

When arguing against a “common misconception,” one typically provides a source. You seem to be saying that Apple’s claims are not only wrong, but ObjC is somehow faster despite having to do more work. Swift has no runtime method table lookups, no extra objc_msgSend calls, better ability to analyze and inline code, no retain/release dance for code with value semantics, etc. Every benchmark I’ve seen shows Swift faster…

Do you have experience writing Swift or Obj-C programs? My experience is that Obj-C has predictable performance which is often "good enough", whereas Swift is either too slow (without optimizations) or takes a very long time to compile (with optimizations enabled).

As a concrete example, I took a Swift program I had lying around (8 files, 2854 lines total), compiled it without optimizations, and stress-tested it a bit. Here's what the "bottom-up" profile looks like: https://i.imgur.com/ohlKQgx.png -- tons of time wasted in Swift runtime overhead. Compiling with optimizations removes most of the overhead, but a clean build of this (relatively small) program took almost 5 minutes with optimizations enabled.

Post reply on HN