As Metal Language is also based on C++11, and C++ would seem to be a perfect fit which is a proven performance language, i am looking to altogether bypass Objective-C / Swift. I would love to remain in C++ arena. Is there a possibility?
5 Answers
Technically yes, but it'd be extremely ugly and might break some other Objective-C parts.
Objective-C, like C++, started life as a preprocessor. One of the legacies of that is that every Objective-C method is also exposed as a C function call that takes the object instance and the method selector as the first two arguments respectively, then the other declared arguments in left-to-right order.
Both NSObject
and the C calls that form the Objective-C runtime can look up the current C function that would be called for any method call.
You could therefore create a C++ class that grabbed all the C function pointers (it could even do this from the C runtime, making it pure C++ code and not Objective-C++) and jumped straight to the appropriate code like that.
The downsides are: Objective-C normally uses dynamic dispatch (i.e. method resolved to C function on each call) and mechanisms like key-value observing work only because it uses dynamic dispatch. If you grab the C function pointer before someone else starts observing then your calls are going to make to update the property without notifying observers. So you're potentially going to break some modules.
That warning being issued, and assuming you can just build your C++ bridge class as Objective-C++ for simpler syntax e.g.
class MTLArray {
id m_instance;
static NSUInteger (* s_arrayLength)(id object, SEL selector);
};
MTLArray::MTLArray() {
// assuming you use the m_ pattern for instance variables
m_instance = [MTLArray new];
// assuming you use s_ for static variables; also pretending
// the mapping from method to C function will never change —
// KVO is the most prominent exception but otherwise you can
// be exceedingly confident, albeit you'll be relying on
// empirical behaviour, not the formal contract
if(!s_arrayLength) {
s_arrayLength = [MTLArray instanceMethodForSelector:@selector(arrayLength)];
}
}
NSUInteger MTLArray::getArrayLength() {
return s_arrayLength(m_instance, @selector(arrayLength));
}
... where I've conveniently declined to cast the result of +instanceMethodForSelector:
to the appropriate type because I'm confident I'll get it wrong. I tend to chicken out and introduce an intermediate typedef
in my actual code but you may prefer to be more terse.

- 99,986
- 12
- 185
- 204
-
3Sure, by implementing this dangerous quasi-static dispatch, you avoid one call to objc_msgSend, but that IMP still refers to a function that's almost certainly going to call other Objective-C methods. Thus my assertion that it's impossible to "altogether bypass" Objective-C as the OP requested. – warrenm Jan 19 '15 at 00:40
-
1@warrenm agreed: this approach is (i) dangerous; and (ii) at best quasi-static. But I'm optimistic that the runtime points it makes will give the author sufficient knowledge to know what he's looking for; he's a C++/Metal programmer after all, so he's clearly happy with machine-level thought. Also I'd quibble on describing this merely as saving the call to objc_msgSend as though the stack frame setup is the cost — it's the dynamic dispatch that I would assume he wants to avoid. You imply you doubt there's any point, that the cost is negligible. If so then I agree. – Tommy Jan 19 '15 at 06:33
-
It has nought to do with what level of abstraction he's comfortable operating at, and everything to do with your answer not actually addressing the question at hand. – warrenm Jan 19 '15 at 17:04
-
1@warrenm the question at hand is "Is there a possibility [of using C++ directly with the Metal API]?". If you think my answer doesn't address that then we disagree. – Tommy Jan 19 '15 at 17:46
-
It would seem we have different fixations. Your answer is focused on using Metal "directly" from C++. Even then, it's a poor solution; you'd be better off just wrapping Metal with Objective-C++ classes, since there is absolutely no way to actually remove Objective-C from the equation. I'm harping on the phrase "altogether bypass," which to me clearly indicated that OP wanted a solution that does, in fact, circumvent Objective-C entirely (i.e., gets at the C or C++ implementation that _underlies_ the Objective-C façade of Metal). Your answer simply does not fill the bill in that regard. – warrenm Jan 19 '15 at 17:59
No. Metal is exposed only as an Objective-C API. At best, you could wrap it with a set of Objective-C++ classes, but that would only add overhead, instead of bypassing Objective-C as you desire.

- 31,094
- 6
- 92
- 116
If you want to use Objective-C APIs, but work primarily in C++, your best bet is Objective-C++. This is just Objective-C, but using C++ instead of C as the underlying language.
To convert an Objective-C class to Objective-C++, just change the suffix of the source file from ".m" to ".mm". (You'll also need to make sure to include the proper C++ runtime library at link time.)
Once you've do this, you can use C++ code inside your Objective-C methods, including template types like std::vector as well as C++11 constructs like range-based for loops.

- 619
- 7
- 17
Yes! Apple now provide an official Metal C++ wrapper.
This download also provides C++ wrappers for some Foundation and QuartzCore classes as well, however it's not obvious how you are supposed to integrate the C++ classes into an app using MetalKit, which is what you are likely to be using these days...
EDIT: Having tried it, I would not recommend it. Having converted my small Objective-C++ project over to using it this evening it did not work and it was not obvious why (crashes in sendMessage
).
It's also much more work to manage the reference counting than using Objective-C++ where you use id<MTLWhatever>
and ARC does the work for you.
As far as converting from an Objective-C object to a C++ object, it's a simple bridging-cast:
// In MyClass.cpp
MyClass::~MyClass()
{
if (_buffer != nullptr)
_buffer->release();
}
void MyClass::setBuffer(MTL::Buffer* buffer)
{
if (_buffer != nullptr)
_buffer->release();
_buffer = buffer->retain();
}
// In SomeClass.mm
id<MTLBuffer> inBuf = ...;
myClass.setBuffer((__bridge MTL::Buffer*)inBuf);

- 120,358
- 21
- 212
- 242
-
Do you still see crashes in `sendMessage`? Seems like Apple would either want to eventually fix that, or claim they no longer support the API... – SO_fix_the_vote_sorting_bug Apr 16 '22 at 16:14
-
@SO_fix_the_vote_sorting_bug I haven't tried it recently. I got better results with my homegrown solution so I stuck to that. – trojanfoe Apr 20 '22 at 09:23