8 ms·
There was a thread the other day where people were talking about languages that were easily interoperable with the "C ABI" (although there is no such thing). La
by btrask 10y ago
There was a thread the other day where people were talking about languages that were easily interoperable with the "C ABI" (although there is no such thing). Languages listed included C++, Rust, and maybe a few others--but no mention of Objective-C.
The ability to use a high-level, dynamic language (ObjC), C, and even inline assembly in a single source file is unique to Objective-C (at least among the "mainstream" languages), and something I think is often under-appreciated.
One comment on the code here: for message calls returning type 'id' (object type), you don't need to cast the dispatch function. It would make the code much more readable. For other return types, you need a cast, but I'd wrap it in a macro. You could even use a C11 generic macro to handle floating point return values (unfortunately necessary).
- eridius 10y agoYou do actually need to cast the dispatch function, because there is no guarantee for all platforms that the ABI for calling a variadic function is the same as the ABI for calling a non-variadic function with the same arguments.
- dmytroi 10y agoThanks for the comment! On OS X if OBJC_OLD_DISPATCH_PROTOTYPES is not defined, you will get this declaration with zero arguments: void objc_msgSend(void /* id self, SEL op, ... */ ), which is possible to call from C without cast by using implicit function declaration, but this call will fail if compiled as Objective-C code with error "too many arguments to function call", I've decided to write in a style that compiles as C and Objective-C code. PS. Would be nice to be able to use functions from clang Objective-C runtime [1], but for some reason they are not exposed in the public headers. - [1] http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support http://clang.llvm.org/docs/AutomaticReferenceCounting.html#r...
- mikeash 10y agoYou should still cast the dispatch function even when your return type is id. For one, C vararg type promotion makes it impossible to pass certain types in as parameters otherwise. For example, you can't pass a float. It's also easy to make mistakes because of type mismatches. For example, if you pass `42` to a CGFloat parameter, this works fine when you cast msgSend to the right type, but will fail amusingly if you rely on varargs to make it through. Perhaps most importantly, vararg calls aren't guaranteed to be compatible with a non-vararg target (as most/all methods you call will be), and you'll see this in action on ARM64. Currently, you can #define OBJC_OLD_DISPATCH_PROTOTYPES 0 to have the compiler enforce this requirement. (This declares the functions to take (void) rather than (id, SEL, ...).) It's likely that Apple will eventually make this the default.
- btrask 10y agoYou're right and thanks for the correction. One point I'd add is that C generally encourages not using casts because casts themselves can be error-prone. So it's debatable whether it adds any real type-safety.
- mikeash 10y agoI don't see how it's debatable. The version without a cast is just plain incorrect, but happens to work anyway through luck and happenstance on many platforms. Even ignoring that, getting the types right without the cast requires looking at the type of every parameter, which could be variables declared far away, and understanding and applying C's vararg type promotion rules. Getting the types right for a cast just requires writing out those types correctly at the point of the cast.
- btrask 10y agoI said you're right and I wasn't trying to disagree. I'm also a big fan of your blog and comments here (FWIW). As for whether casts add much safety, I admitted it's debatable. C++ prefers casts (e.g. on malloc) whereas C doesn't. A downside of using explicit casts is that if the type changes elsewhere in the program, the casts (spread throughout the code) can mask errors. If you write code such that casts are unnecessary (which I'm agreeing is not possible in this case!), you will get a compile warning/error right away. I think both perspectives are valid and there are risks either way. I try to avoid casts when writing plain C though.
- mikeash 10y agoI agree that unnecessary casts are undesirable, but that seems like a completely irrelevant point here, seeing as how the casts are not optional. C++ doesn't prefer casts, it requires them in places where C doesn't. Casting the return value from malloc isn't optional in C++ (unless you're assigning to a void *, anyway).
- 10y ago
- radarsat1 10y agoSo I will bite. Why does the C ABI not exist? C calling conventions (cdecl, stdcall) and memory layout is pretty well standardized. So I'm not sure what else you could be referring to here.
- umanwizard 10y agoNot OP but I'm guessing they were referring to the fact that this stuff is platform-specific and not specified by the C standard.
- msbarnett 10y agoThe C standard specifies absolutely no "C ABI" standard. The two "standard" calling conventions you cite, cdecl and stdcall, are Wintel conventions. However, since C is the low-level implementation language for almost every dominant operating system, a given platform's Operating System ABI is almost always locally synonymous with the C ABI on that platform, and people tend to speak of "being compatible with the C ABI" when what they really mean is that they're compatible with the OS's ABI. But if you move to, say, a Mainframe OS, the OS ABI is dramatically different than the "C ABI" you're imagining from Wintel.
- btrask 10y agoEven on a platform that wasn't based on C, the C standard is flexible enough to match pretty much any native ABI. That's a small (and under-used) upside to all of that undefined behavior.
- Someone 10y agoMost of the time, you will need a tiny bit of non-standard stuff in your compiler to do so. For example, I don't think there is a portable way to let your compiler use Pascal calling conventions, or to pass information in specific registers or in processor flags. As an extreme example, in classic Mac OS, you could register a function to be called for line breaking in text input boxes that had the ABI "Parameters are passed to the routine in registers A3, A4, and D0, and output is returned in the Z flag of the Status Register." (https://developer.apple.com/legacy/library/documentation/mac/pdf/PPC_System_Software/Mixed_Mode_Mgr.pdf https://developer.apple.com/legacy/library/documentation/mac..., page 2-31 gives several other special-cased ABI's in Mac OS) Browsing that, I also encountered "The routine follows the C calling conventions employed by the THINK C software development environment. Arguments are passed on the stack from right to left, and a result is returned in register D0." (Aside: that compiler must have treated vararg functions differently) So, apparently, one cannot even count on C compilers to push arguments from left to right. So, if your ABI says "push X first, then y", I don't think you can portably call that function from C.
- conradev 10y ago> The ability to use a high-level, dynamic language (ObjC), C, and even inline assembly in a single source file is unique to Objective-C (at least among the "mainstream" languages), and something I think is often under-appreciated. You can even use C++, too, which is awesome. Putting Objective-C objects in C++ structs "just works" thanks to ARC. One thing most people don't know is that Objective-C was originally implemented as a precompiler for C.
- dep_b 10y agoI think it actually was a precompiler for C up til a point. Still Objective-C objects have underlying C functions that are being called whenever you try to call a method or anything on an Objective-C object. Theoretically you should be able to call functions on Objective-C objects from C.
- conradev 10y ago> Still Objective-C objects have underlying C functions that are being called whenever you try to call a method or anything on an Objective-C object. The same goes for C++ or Swift. Getting the function pointer for a method can be involved, but all functions adhere to the C ABI.
- poizan42 10y agoAt least MSVC on x86 uses "thiscall" by default which puts the this pointer in ecx. You cannot call those functions from C without specific compiler support.
- vardump 10y agoSure you can. Just write an asm stub to call, that sets up ecx and other things right.
- poizan42 10y agoThe claim was: The same goes for C++ or Swift. Getting the function pointer for a method can be involved, but all functions adhere to the C ABI. This is clearly false since at least one C++ compiler generates functions that does not adhere to any of the common calling conventions for C on that platform (or "C ABIs" if you will). Besides that, I said you could not call them from C. An asm stub is not C. Neither is inline assembly even though it's a common extension to C.
- gumby 10y agoSVR4 specified standard-conformant calling conventions (stack layout, register use etc). IIRC VMS went one "better" and tried to specify a standard calling convention that was supposed to apply to all programs (sadly, there's more to interoperability than calling convention).
- avar 10y ago> The ability to use a high-level, dynamic language (ObjC), > C, and even inline assembly in a single source file > is unique to Objective-C (at least among the > "mainstream" languages)[...] Well Perl is mainstream enough to be installed on every *nix box, here's examples of assembly and C functions interoperating with Perl in the same source file: https://metacpan.org/pod/distribution/Inline-ASM/ASM.pod#SYNOPSIS https://metacpan.org/pod/distribution/Inline-ASM/ASM.pod#SYN... & https://metacpan.org/pod/distribution/Inline-C/lib/Inline/C.pod#Example-1---Greetings https://metacpan.org/pod/distribution/Inline-C/lib/Inline/C.... > The "C ABI" (although there is no such thing) Of course if you do this in Perl every one of your calls will need to go through a foreign function interface where Perl's structures are translated back & forth between its idea of datastructures and the OS's idea, avoiding that is what people really mean when they talk about the "C ABI".
- mintplant 10y agoHaskell has support for inline C [1] and inline Objective-C [2] implemented as libraries. [1] https://github.com/fpco/inline-c/blob/master/README.md https://github.com/fpco/inline-c/blob/master/README.md [2] https://hackage.haskell.org/package/language-c-inline https://hackage.haskell.org/package/language-c-inline
- jheriko 10y agonot really. MS have had this with their C++ for a very long time... easily 20 years +
- chillacy 10y agoUnless MS has a custom C++ runtime that I'm not aware of, I wouldn't consider C++ a high level language like obj-c is, for better or worse. The benefits and drawbacks of runtime dispatch are highly debatable, but the amount of runtime metaprogramming you can do in ObjC is comparable to what you can do in a language like Ruby: * Call any method (send message in objc parlance) based on the string name of the method * Add methods to existing classes you don't own * Swap existing method implementations of a class you do not own at runtime (method swizzling) * Get and set variables by their string name for subclasses of NSObject * Check if an object has a method with a given name (great for invoking methods conditionally) http://genius.com/Soroush-khanlou-objective-c-isnt-what-you-think-it-is-if-you-think-like-a-rubyist-annotated http://genius.com/Soroush-khanlou-objective-c-isnt-what-you-...
- themartorana 10y agoI'm going to miss Objective C terribly. It is, hands down, still my favorite language (and ecosystem). It's interoperability with C got me into C. It was insanely powerful and fun. I know not many people agree with me. I liked the square braces and crazy long function names. I know Swift is decent... It's not the same. Oh well. Lamenting my path to software engineering doesn't mean much for anyone else. But I really am going to miss it.
- deleted 10y ago[deleted]
- josh64 10y agoI feel the exact same way about it but hopefully it isn't going to go anywhere any time soon. WWDC 2016 will hopefully have some nice objective C announcements just like last years did.
- informatimago 10y agoWhy miss it? Just go on using it! If important applications are written in Objective-C, that will motivate the spreading of Objective-C.
- gcr 10y agoIs objective-C going away? Also, are there any particular resources that you would recommend for beginners? I'm looking forward to reading this article since it might expose the low-level details of how, say, message passing works under the hood. Most of the guides are a bit too "beginner-oriented"; I'd love to find something that pulls up the carpets to reveal all the infrastructure underneath.
- themartorana 10y agoSwift is the future Apple is pushing to developers. There is an insane amount of Objective C in the world for sure, so it's not going away completely, but I expect more new work will choose Swift, and eventually Objective C will be relegated to Apple devs working on OS X itself, plus legacy apps. But maybe I'm wrong, and I'd be happy if I were.