In defence of Objective-C
splinter.com.au
splinter.com.au
After doing a couple of projects with it I've found it to be a really beautiful language from a code formatting point of view.
The whole 'overly verbose' thing is probably just because you are encouraged to give your methods and arguments good descriptive names, and often when you do need short variable names for some maths calculations or something it will be while inside a method block using good old C style anyway.
I don't know, it's flexible, (arguably) attractive and it runs fast.
Yay Objective-C! :)
Now I have no desire to incite a language flamewar (to each their own blub!), so I will leave it at that ;)
But it's nice to see a semi-tutorial wrapped in an argument. Arguments are more fun to read than tutorials, so I picked up a few factoids (named args) without having to read Apple's documentation (which is a little dry).
filteredArray = [allRecords filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:@"someField == %d", someFieldFilterValue]];
A four-word name for filter and filtering for equality by using a string formatting DSL are not really on my list of lovely things. I'm sure Objective-C does something well but this guy is not pointing it out.Maybe the whole essay would have been better framed something like: "Objective C: not quite as bad as Java!"
At least that's one way to do it in ruby.
filteredArray = [allRecords filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:@"someField == %d", someFieldFilterValue]];
in ruby: all_records.select {|r| r.some_field == some_field_filter_value}
in clojure: (filter #(= % some-filter-value) all-records)
in haskell: filter (\someField -> x == someFilterValue) allRecords NSIndexSet *indicies = [allRecords indexesOfObjectsPassingTest:^ (id obj, NSUInteger idx, BOOL *stop) { return [obj someField] == someFieldFilterValue; }];
filteredArray = [allRecords objectsAtIndexes:indicies];
rather than what the article had in mind.EDIT: oh, someFieldFilterValue was an integer, wasn't it. Fixed.
filteredArray = allRecords.Find(i => i.someField == filterValue)
EDIT: Not sure why the downvote, I'm simply stating that many other languages have far better syntax for filtering an array so I'm not sure why the author would think the syntax in Obj-c is all that great unless they have never done the same thing in any other language.
To quickly address this issues, before discussing the real problems: "Ugly" - get over it, "Verbose" - get over it, "Memory Management" - Obj-C memory management is in fact super simple as long as you follow some really simple rules, especially with ARC.
Now the real problems I have:
1. Lots of unnecessary code. With the old runtime, you had to modify your code at four (!) places to introduce a new property in a class. With the new runtime, that has decreased to three, with ARC, to only 2, but that's still one more than what should really be necessary (@synthetize should go).
2. The whole header file thing. I know that Obj-C is a descendant and strict superset of C but I still find separating header files from .m files somewhat tedious and unnecessary. This leads to
3. Having to declare methods and properties before you use them. I mean, this is 2011, this shouldn't be necessary.
4. The syntax for having "private" methods and properties is awkward even by Obj-C standards. Basically you have to create an anonymous category in the implementation file.
5. Properties (with ARC) should default to strong for objects, assign for everything else.
6. The [[X alloc] init] way to construct objects; I understand that from a theoretical point of view it's cool to separate allocation from initialisation but I've never ever needed to allocate an object with anything other than the alloc message.
7. The debugger. GDB and Xcode are atrocious. Have a look at the C# debugger in Visual Studio; that's how a debugger should look like.
Overall, while a lot has been improved recently in Obj-C, my main gripes with the language all come from the facts that it's a C superset (which is also a massive advantage) and that it's an almost 30 years old language; the programming world was very different 30 years ago.
Also, I would love to be able to do some kind of metaprogramming without resorting to strings.
Once it matures I expect the Xcode debugging experience will become quite a bit different from the current (flimsy) gdb shell-out.
8. Global space is polluted with constants and enums
[NSMutableDictionary dictionaryWithConstructorIDontWantToType:...]
is just a huge pain in the ass. Other problems with the syntax have been solved by introducing sugar at the right place. Why not
id hash=@{ @"key" : @"value };
and id array=@[ @"value1", @"value2", @"value3"];MyArray *array = [[MyArray alloc] initWithObjects:@"string1",@"string2",...];
Lets understand this in two steps:
Step 1) You first allocate an object of type NSArray by passing a message "alloc" to the NSArray Class object.Yes every class in objective C is really a class object in the Objective C runtime.Now this class object may allocate data or it may not.It may also return you a pointer to a previously allocated object(Yes that is a cool way of implementing the singleton pattern.In any case it will return you a pointer to an allocated memory space or nil.
Step 2) Now you tell the allocated object how to initialize itself.The allocated object may have been already initialized and it might just append the strings.The allocated object might be nil.
What I am trying to point out is that there is a lot of dynamism involved in writing an initialization in a two step message passing.It almost feels like the objects are alive.My opinion is that this is real object oriented programming.
In this specific case, you actually can usually use "arrayWithObjects:" (yes, the syntax that the poster didn't like), and it is frankly preferred. If you are doing alloc/init, and (as in your example) storing to a local variable, you should also send an autorelease in the same statement, so as to guarantee exception safety of allocation for subsequent code; "arrayWithObjects:" takes care of all three steps for you.
Although the latter approach can be taken by using macros ,I was making an argument for the beauty of the first approach.For example it would not be possible to allocate a singleton object with a line like that in Python.
We use it in a lot of our code here. Its quite nice. You'll end up with something like:
myDict = $mdict(val, key, val2, key2);
#define KV(KEY,VALUE) VALUE, KEY
myDict = MD(KV(key,val), KV(key2,val2));
Ugly but a case can be made that this end justifies the means.Another option is implementing your own dictionaryWithObjectsAndKeys where you flip the varargs and feed them back into the subclass dictionaryWithObjectsAndKeys.
#define MD(val, key, vals...) [NSMutableDictionary dictionaryWithObjectsAndKeys:val, key, ## vals , nil]
then do:
NSMutableDictionary* dict = MD(@"value1", @"key1", @"value2", @"key2")
And so on. Courtesy of http://news.ycombinator.com/item?id=1789839.
#define MD(...) [NSMutableDictionary dictionaryWithObjectsAndKeys:__VA_ARGS__, nil]But for MD(val, key, vals...), it'd give you a slightly better error, complaining about the number of arguments when you do MD().
Otherwise they are the same in this case.
## removes one non-whitespace character – often the comma – before the ## if vals or __VA_ARGS__ is empty.
e.g
#define MO_LogDebug(fmt, ...) NSLog((@"DEBUG " fmt), ##__VA_ARGS__)
MO_LogDebug(@"This works as expected %d", resultCode);
// Removes the comma automatically in here:
// NSLog((@"DEBUG " @"This works too without args"), );
MO_LogDebug(@"This works too without args");Languages that some look at as "real programming languages", in comparison, tend to not have syntax like this, and the reason why is that you often, either now, or at some point later, are going to care whether the data structure you just allocated is a red-black tree, a hash map, a patricia trie, or even an AVL tree (which I include mostly to make a point: there actually are situations where it is preferred to a red-black tree).
When this suddenly matters, you are in the situation where what you want to be able to do is to make a very small modification to areas of your code where you need to select a different algorithm, in order to get the different result; you don't want to be forced to rewrite half your code to use a different syntax just because it was slow (I mean, if you wanted to do that, you'd have written it in Ruby and then recoded it in C).
Therefore, you find that it is normally the case in languages like Java, C++, and Objective-C, that there are no "built-in container types", as you will never find a container type that is actually correct to use in an even fractional majority of the cases; in fact, most of the time, there isn't even a single obvious choice in these languages for what class to use: you find default implementations of multiple algorithms.
Objective-C, here, is no different from this concept: NSDictionary is just an interface, and can be implemented by numerous backends. Apple has a rather good implementation backing the default version, and even attempts to switch between algorithms as the data structure grows, but your code is always just a few identifiers away from choosing a different subclass in that collection hierarchy.
(C++11 is actually an interesting thing to analyze regarding this tradeoff, by the way: the new "common initializer" syntax is designed to provide as much of the benefits as possible of a simplified built-in data type syntax without taking on the semantic burden of having it; however, it also does not provide syntax that ends up being entirely devoid of the type of the container.)
You can't redefine haskell's syntax unless you're using Template Haskell (which is a language extension, not part of Haskell itself). It also has nothing to do with monads. Likewise with most MLs, or with Erlang. All of them have a literal list syntax.
And if containers have no reason to be special, why would strings be special? They're just sequences of unicode codepoints after all.
Continuing your argument into absurdity, why have literal syntax for most datatype at all really? You could just shove a bag of bytes into a constructor when you want integers or floats as well. Now you've got one literal syntax (which isn't even for a datatype): bunch of bytes.
As for strings, it is very seldom that you find interesting alternative implementations: the only one I can think of is a rope. Interestingly, C++11 now allows you to override string literals, so you can actually do this.
Sure but it's not syntax redefinition.
> Interestingly, C++11 now allows you to override string literals, so you can actually do this.
You still have a literal string notation. Literal notations don't have to impede multiple implemetations, and the truth is there is generally a primary representation used for the vast majority of cases (even if that representation is a cluster class and flexible under the interface).
In Cocoa, the primary sequence and maps are NSArray and NSDictionary, what would be the issue with making those literal? And one of your objections is
> When this suddenly matters, you are in the situation where what you want to be able to do is to make a very small modification to areas of your code where you need to select a different algorithm, in order to get the different result; you don't want to be forced to rewrite half your code to use a different syntax just because it was slow
But that makes no sense: as long as all equivalent containers implement the same interface (which they do, or you can't swap them anyway) that creating an object be done with a literal or with a constructor and a bunch of messages has no influence on the rest of the code, the only thing you need to change is the initialization code in both cases.
Hell, a smart enough editor can even swap between the literal and the "constructor" versions of a given collection (IntelliJ can do that for Python dicts, for instance). Not to mention in many cases the non-literal can just take the literal as a parameter, if the collection with a literal syntax has been well chosen, that way you get your cake eat it.
http://gcc.gnu.org/onlinedocs/gcc/Constant-string-objects.ht...
I will also, though, point out that I write almost as much (if not more) Python as I do Objective-C++ these days: I therefore can be said to certainly not consider Python to be for "stupid people", without including myself in that set. ;P
Tab completion of methods is very nice to have, and makes using xcode as fast as using vim for me. (now, if I could have vim keybindings with xcode tab-complete, then I'd rocket through my editing...)
I'd love to know what Eclipse/VS/NetBeans users think about it, maybe it's easier if you're already used to working inside a huge IDE.
Most of the problems I've hit with iOS development are Xcode-isms.
I've recently been sent on a merry hunt to get the built-in git integration from imploding, and the project groups vs folders ambiguity has caused mistakes of the "what actual file is this name pointing too again?" variety (and this in turn leads back to the git integration issues when a file is not where you think it is).
It would also be nice if Objective-C++ was a first class citizen with regards to refactoring tools (I understand this might be hard to implement however).
Rarely has it been a problem with the actual language itself.
I have such a strong dislike for Objective-C, I can't explain it. I mean C++ is insane in a way, and Haskell is a pure Mindbender. But Objective-C's syntax, to me, is indeed so verbose, I'd rather read the EU regulations on "the common organisation of agricultural markets".
I had to create a couple of iPhone apps, and I probably will have to create some more in the future.
Is there any way for me to overcome my unnatural dislike for this language?
And yeah, this article did not work for me, as you would have already guessed.
Grow some taste?
(filter foo? all-records)
Yeah, maybe not so much.1. The first major point (which is found at the end of this post) in any "defense of Obj-C" should be that this is a very pragmatic language. It makes a lot of wise tradeoffs and rarely strives for "purity" or "religion". This helps to put a lot of the language choices in context, and actually is the strongest reason its a great language in my opinion.
2. "Ugly" - The point is certainly not that you "see through the brackets", that's a terrible argument! The point is to understand why we have brackets, because they allow for named arguments without colliding with existing C syntax. Additionally, they make it clear to the user that what is about to happen is not a traditional method call, it is a message send. This is because you can do both in Obj-C (not to mention Obj-C++).
3. "Verbose" - First off this is a framework decision. It's possible to take Obj-C without Cocoa, and write a framework that is just as non-verbose as Python (and vice versa). But fine, you could make the argument that the named parameters "encourage" verbosity if you want. The key here is not to hand wave this away as a matter of "taste", but to understand the logic behind this: its very easy to read. I can show lots of non-programmers Obj-C code, and it really reads like english. In fact if you just read aloud many Obj-C snippets, it often sounds very close to English. 80% of coding is reading code, and if you work on a big project, its reading other people's code. You never run into a piece of code that has 4 arguments and have no idea what the last "true" is for. Similarly, you never have appendChild(node1, node2) moments where you're not sure which is the node you're appending and which is the one being appended next to. Apple's SDK's are repeatedly praised and a big part of that is that the frameworks are very friendly. I personally find the opposite trend of terseness incredibly strange: why do we focus so much on shrinking variable names.
4. "Memory Management" - This I will admit was more or less fair. The MM story just isn't that great with Obj-C. I have to admit I thought it wasn't a big deal before spending a lot of time in a dynamic language, but it really is annoying coming back to it. And while I'm not 100% sure yet, ARC is not the be all end all. I have to say I think about memory almost just as much with ARC (perhaps simply because I'm not used to it). At least with explicit management I knew exactly what was going on, with ARC I kind of feel that its half magic and half really hard situations. I really hope I'll eat my words about this soon. Now, the counter argument is that this is why Obj-C is so fast. I honestly don't know if that's true. I know enough smart people on both sides of the argument to say that I simply don't know enough about it.
With this realization, Objective-C is actually really good at this, requiring many fewer (if not actually no) try/catch blocks to get "safe" code than is required on seemingly almost every line of Java (which doesn't even have C#'s "using" to help it out, a primitive that causes its own problems due to lack of contracts), and has conventions that make it quite simple to "locally" (as in, without having to read anything not directly around the area you are analyzing) determine whether code you are looking at is handling things correctly.
Therefore, and I kid you not: when I saw "a defense of Objective-C" I was anticipating an article that was going to start with how awesome the memory management was (listing the auto-release pool paradigm as something that people typically haven't developed into mature C++ memory paradigms), followed by a discussion of the balanced tradeoff between fully dynamic typing and dispatch with low-level performance-oriented code; instead, I read "You’ll have to prise my garbage collecter out of my cold, dead hands!", sigh, and go back to coding. :(
for the record: My preference for Smalltalk-style messaging over Simula-style objects is largely historical (having been exposed to the former first)
I think I have a solid understanding of both models and how to work with each, but as far as syntax goes I'm fairly ambivalent (granted, most of my code is in C/assembly).
The number of programs you can write without file handles, database connections or minimum-wage bicycle messengers is dwarfed by the number of programs that are extremely painful to write without dynamic memory allocation. We can argue all day about how 'fundamental' the difference is but there is a profound practical difference well-recognized in the decades of work that's gone into memory GC. 'It's ok/actually awesome that Obj-C kind of blows at memory management because other languages kind of blow at universal resource management' is a pretty specious argument.
Many languages, including Objective-C (although, arguably/mostly Foundation), manage to provide primitives that make it easy to manage either at once; the only high-level complexity you have to give up is cycle detection, which is a serious problem and "known tradeoff" in many fields, including deadlock detection (hence, why I mention an interesting connection to things like CAP).
Also, I would also love to see a reasonable program that does not have external resources: I find that almost all the work my programs are doing are managing and moving around external resources... from threads to sockets to money, you are probably not doing anything terribly useful unless you are dealing with a non-memory resource.
Regardless, the goal of these statements is "a defense of Objective-C", not "why Objective-C is amazing": the "defense of Java", when you show someone a four-level nested try/finally whose sole purpose is to make non-deterministic finalization of File objects exception-safe, is "but we have garbage collection, which has these nifty properties, including automatic cycle detection".
I don't think you need a reference - when we discuss algorithms we have a notation to describe an algorithm's behaviour in time and space yet never bicycle messengers. If anything, this suggests these resources are, indeed, somehow (and obviously) more fundamental.
The 'defense of Obj-C' article thing is pretty silly, no argument there.
Additionally, as I think this is also relevant to your comment, if you take a step back for a second from the notion that an object /is/ memory, and think of memory as being one of the resources that an object is using, things become more clear.
Simply put, we have two common ways of reclaiming objects automatically: garbage collection and reference counting. The tradeoff is that with garbage collection, you get free cycle detection at the cost of not having deterministic finalization.
Each of these options has downsides: neither is fundamentally better than the other, and not having either one causes you to have to scratch your head occasionally, or add extra code to deal with the lack of automation.
(edit:)
Thinking about this overly simple description, I realize that I'm over-simplifying a little too much... a lot of the fundamental problem has to do with an inability to determine the order of finalization of objects in a cycle, which is what causes a lot of mistakes in Java finalizer implementations.
In comparison, the practical problems are that the common implementations involved take extreme positions: if you have a garbage collected language, it normally is not "reference counting with a cycle detector bolted on", which yields a weird property of possibly arbitrary delays on finalization of valuable resources when you aren't under memory pressure.
And GC is always less efficient than no GC, even with more memory.
The thing is that Malloc isn't particularly smart about how memory is allocated so you can end up with various tangles, etc.
On the other hand if you have enough memory you can do a hole world copy which, among other things, means that allocating memory is O(1). This is better than malloc if you have short lived and small objects.
If your available memory is less than five times the working-set size, GC is less efficient than some sort of malloc/free perhaps with reference counting
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.61.9...
The reference counting would only be used in certain cases where the dynamic extent of the object is unknown. Most objects can be cleaned up with an implicit management scheme like the RAII pattern in C++.
No, it's not. GC allows for more efficiency in many scenarios. Imagine creating and destroying many small objects. With traditional memory management, every malloc incurs a cost to allocate a chunk of memory from the free store. This will involve some work to break the correct-sized piece of memory off some larger block, and some bookkeeping for later restoring that memory to the block and possibly enlarging the block, merging with others, etc.
On the other hand, in a modern generational GC, a malloc typically consists of adjusting a single pointer to the nursery pool by the size requested.
Depending on the scenario, GC can be just as fast, or even faster. In other scenarios, manual memory management may be faster.
This manual work incurs a penalty only for the developer, not for the performance. And you get to fine tune your memory allocations to your program's behavior.
> in a modern generational GC, a malloc typically consists of adjusting a single pointer to the nursery pool by the size requested.
Sure, but by "less efficient" I'm not only referring to allocation speed, but also to memory usage. That nursery pool is auto-managed, and not program specific (with the exception of some smart gc guesses).
And GC can be more efficient in terms of memory usage as well. Modern GCs compact and so avoid most loss due to fragmentation. Where malloc will generally leave blocks partially unused, GC can allocate objects consecutively with no space between them, even if the objects vary in size (though there may be loss due to alignment, but that loss will occur in any memory management scheme).
Garbage collected languages prevent this sort of thing from working, because they force overhead, and even though they might be able to do better than a lazy programmer, a person who cares about what they are doing will do ok.
"Pragmatic", much like "practical", is utterly worthless for programming language discussions. It means something different to everybody, and it's basically the tool you'll reach for when you have absolutely nothing good to say about the language you're trying to "defend".
Both "pragmatic" and "practical" should be the godwin points of PL discussion. They're complete bull.
> The point is to understand why we have brackets, because they allow for named arguments without colliding with existing C syntax.
Just because there are reasons it's done that way does not mean it's any less ugly, does it?
> Additionally, they make it clear to the user that what is about to happen is not a traditional method call, it is a message send.
For pretty much all OO PL languages, the distinction is just cutesy, the end result is that you're synchronously calling a method on an object, whether you call it "message" or "method" has little relevance.
> This is because you can do both in Obj-C
Do you mean that in a "function pointer in a struct" sense? This would use the `->` sigil would it not? And obj-c 2.0 managed to include dotted property names, so that could have been used (obviously, it wasn't because obj-c merges Smalltalk syntax into C and Smalltalk's message-send syntax does conflict with C if unbracketed)
> It's possible to take Obj-C without Cocoa, and write a framework that is just as non-verbose as Python
Not quite, Obj-C has structural deficiencies (in part inherited from C) which mean it has boilerplate you can't do without, such as the duplications between header and implementation files.
For much of its history, it also lacked any form of "blocks" (and those added in obj-c 2 are pretty verbose), meaning your Obj-C code would have a harder time with scoped resources than the equivalent Python code.
Other intrinsic verbosity issues of obj-c: iterations pre-Obj-C-2 (and fast iterators), type annotations, retain/release calls (we'll see how ARC fares), ...
I would say embracing Cocoa's chosen verbosity (although I sometimes find it misplaced) is a much better strategy than claiming Obj-C can be as terse as Python.
Huh? Design patterns are "thankfully not there"? What does that even mean?
Though, to be fair, my exposure to the community is limited to AP CS AB (why they decided to use java is beyond me ...)
Arguably, this is true: many of the patterns simply "fall away" if you have access to features like multi-method dispatch (Lisp+CLOS), message passing with transparent proxying (as in SmallTalk, and to some extent Objective-C), or continuations (Lisp/Scheme).
However, the argument often goes even further into the realm of complaints against "all kinds of patterns, even those that tend to exist in all abstractions, even mathematical ones", deriding things like factories as "overly-complex" (in the same concept of "overly-complex" that make some people choose NoSQL over RDBMS not for scalability, but due to the common lack of schemas).
Wow, you guys really are reading a lot into what i've written, keep in mind that this was written as a light-hearted and hopefully factual rebuttal to all the anti-iphone/objc trolling at my work. Peace :)
NSArray* array = [NSArray new];
And the implementation changes to suit what you're doing with the array rather than CollectionFactory colFactory = new CollectionFactory();
ICollection array = colFactory.getArrayOptimizedFor(100);
Java: It's factories, all the way down.For me, writing articles like this is as much about learning to be a better communicator as anything, and you've (indirectly) really got me thinking about how i could have written this better.
I'm thinking there should be a single 'theme' to an article, and that every topic/point discussed should be related to that theme. In the case of this blog post, it should have been 'pragmatism' as you identified.
If i had written with that in mind, i could have used every point to illustrate how obj-c really reflects pragmatic principles in so many ways, which would have been a much better article.
Your first two code samples are about twice as wide as the space allowed for them, so they are hard to read (horizontal scrolling on text is bad).
Trust me, it grows on you. You’ll soon learn to see through the brackets – just like the green vertical text in the matrix, it becomes invisible after a while. -end quote-
Its ironic that a Lisp/Scheme person would say the same as to why s-expressions are good (the parens become invisible!) so I don't see why objective-c syntax is better but somehow uses the same reasoning.
@I @hope @that @also @applies @to @the @the @at-@signs. ;-)
See also the App Store policies. Apple's priorities tend to be it's users, Apple, then any 3rd party developers. I don't tend to think this is a bad thing...
This is overly simplistic. In their heyday MS catered to developers first and their users second. You can make some snarky comment about this, but at the time it allowed them to become one of the largest and most powerful tech companies out there.
Google catered to it's own engineers first.
The point is there are different ways of building a business; don't blindly choose the Apple path just because they're currently at the top of the heap.
And it works great with code completion. You just type '[' and the editor immediately knows what you are doing. Choose a method and the parameters are right in front of you. No documentation required, unless you actually need in-depth information.
Whereas in other languages you'd have to write... "."?
> Choose a method and the parameters are right in front of you. No documentation required, unless you actually need in-depth information.
Pretty much every somewhat advanced IDE does that, especially for mostly-statically-analyzable languages.
You write "." AFTER you've written the method name. In ObjC "[" immediately tells that you want a method/class name for autocompletion.
filteredArray = [allRecords filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someField == %d", someFieldFilterValue]];
Makes me wonder if the author has ever seen languages that do this like so: let filteredArray = Seq.filter (fun f -> f = "foo") allRecordsXerox PARC, GUI, inspired Steve Jobs, all that fun stuff.
Objective-C is a sort of nerfed Smalltalk bolted onto the side of C. Yes you can see the seams and it's clunky-looking, but it works. Smalltalk semantics means it's much easier to build robust and loosely-coupled programs than in C++, and you don't even occur that much runtime overhead.
I do all my game dev in Objective-C, and I don't even have a Mac that I use actively. In fact I defy people to write significant Objective-C programs that don't use or need the Cocoa or NS libraries. I think they will have an easier and more fun time of it than when working in C++.
If the libraries were designed more like C++'s (say what you will about STL, but at least set<> is called set<>), I'd probably have no issues whatsoever.
[someInstance doSomethingWithObject:a andAnotherParam:b];
It just reads beautifully. Otherwise working with Objective-C was like pulling teeth at times. It had been a long time since I had to write so much code to get such simple things done.
He said: there is no need. In Obj-C the selectors should document themselves.
- Closures (I guess blocks might achieve the same, never worked in Obj-C)
- Lambdas
- Dynamic Typing or Type Inference. You need at least one of those.
- Or any other construct that enhances expressiveness.
Not sure I understand this? How does Obj-c enable the developer to avoid factories?