Can the new Clang Objective-C literals be redirected to custom classes?
You can substitute class for some Objective-C literals with @compatibility_alias
keyword trick.
Here's an example.
@compatibility_alias NSNumber AAA;
Of course, you should provide proper implementation for new class.
#import <Foundation/NSObject.h>
@interface AAA : NSObject
+ (id)numberWithInt:(int)num;
@end
@implementation AAA
+ (id)numberWithInt:(int)num
{
return @"AAAAA!!!"; // Abused type system just to check result.
}
@end
@compatibility_alias NSNumber AAA;
Now Clang will do the job for you. I confirmed this is working for number, array, dictionary literals. Unfortunately string literals seem to be emitted statically, so it won't work.
For more information about @compatibility_alias
keyword, see here.
Note
Because @compatibility_alias
keyword is a compiler directive which applies to current compilation unit, you need to separate compilation unit to avoid symbol duplication with NSObject class in Apple's Foundation Kit. Here's how I did it.
main.m
#import "test.h" // Comes before Foundation Kit.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool
{
NSLog(@"return of test = %@", test());
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
test.h
id test();
test.m
#import "test.h"
#import <Foundation/NSObject.h>
@interface
AAA : NSObject
+ (id)numberWithInt:(int)v;
+ (id)arrayWithObjects:(id*)pobj count:(int)c;
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c;
@end
@implementation AAA
+ (id)numberWithInt:(int)v
{
return @"AAAAA as number!!!";
}
+ (id)arrayWithObjects:(id*)pobj count:(int)c
{
return @"AAAAA as array!!!";
}
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c
{
return @"AAAAA as dictionary!!!";
}
@end
@compatibility_alias NSDictionary AAA;
@compatibility_alias NSArray AAA;
@compatibility_alias NSNumber AAA;
id test()
{
// return @{};
// return @[];
return @55;
}
Result.
2013-03-23 08:54:42.793 return of test = AAAAA!!!
2013-03-23 08:54:42.796 Hello, World!
The comments have it all correct, but just to summarize:
- No.
The meanings of Apple's @{}
, @[]
, and @""
literals are hard-coded into Clang. You can see it here: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup It's all fairly modular, meaning that it wouldn't be hard for a Clang hacker to add her own literal syntax... but "modular" doesn't mean "accessible from the outside". Adding a new syntax or even redirecting the existing syntax to new classes would definitely require rebuilding Clang yourself.
Here's a blog post about adding NSURL
literals to Clang by hacking on its internals: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (Thanks @Josh Caswell)
If you're willing to use Objective-C++ with C++11 extensions, you can has "user-defined literals", which allow you to write things like
NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: @(s)]; }
int main() {
...
NSURL *myurl = "ftp://foo"URL;
...
}
This was mentioned in the comments on Mike Ash's blog. http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html But this doesn't look very Objective-C-ish (or very C++ish!), and it works only with an Objective-C++11 compiler, and in general please don't do this. :)