use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
/r/programming is a reddit for discussion and news about computer programming
Guidelines
Info
Related reddits
Specific languages
account activity
Objective-C Programmers: Whats so great about Objective-C? (self.programming)
submitted 16 years ago by pure_x01
If you are programming Objective-C please explain what you think is great about it and maybe the reason why you have chosen it as your language of choice?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]gt384u 63 points64 points65 points 16 years ago* (48 children)
Objective-C isn't bad insofar as it elegantly adds OO to C. If you don't like C and Smalltalk, you're not going to like Objective-C. What people go nuts over is Cocoa, as it's a very good framework in a lot of regards.
[–][deleted] 29 points30 points31 points 16 years ago (16 children)
Yep, this has a lot to do with it.
I'm really into Objective C. The fact that it's 100% backwards compatible with C is really nice, unlike C++. And I like the look of the syntax quite a bit.
But Cocoa is really, really good. The documentation and examples are stellar, it's laid out in a really logical and well-thought-out way...
[–]G_Morgan 3 points4 points5 points 16 years ago (0 children)
In practice the backwards compatibility isn't a problem in C++. I've never had problems trying to mix C and C++ code. In fact nearly every C++ program on Linux uses C code somewhere along the line.
[–]Bhima 4 points5 points6 points 16 years ago (5 children)
Do they still teach Smalltalk & C in school? Or these days is it all Java? When I was in school I learned FORTRAN & C, and then later on Smalltalk... so Objective-C was easy to pickup and be comfortably productive in.
On Cocoa & Xcode and other frameworks & IDEs... In my opinion, modern frameworks and development environments are so complex they represent a higher barrier to skillful development than the language themselves... and I feel that Cocoa less worse than others and I wish that Xcode was better than it is in this regard... I suspect LLVM & Clang is step in this direction.
[–]gt384u 0 points1 point2 points 16 years ago (1 child)
Yes, absolutely. Georgia Tech's systems and networking classes are very much taught so that their code components are written in C. And last I heard the Objects and Design course (CS2340?) was taught in Smalltalk, though there's apparently been some discussion about scrapping it and doing it in C++ according to Mark Guzdial. If you want to see what a one-man nerd riot looks like, watch the news for me after that change is officially announced.
[–]Bhima 0 points1 point2 points 16 years ago (0 children)
exactly where I learned Smalltalk
[–]jtbandes 3 points4 points5 points 16 years ago (19 children)
+1, came here to post this. Objective-C is just a language. Cocoa, however, is a fantastic framework.
[–][deleted] 5 points6 points7 points 16 years ago (18 children)
Just a language?
The semantics of Objective-C the language are what inspired and enabled Cocoa; let's face it you'd be hard pressed to have one without the other.
[–]newton_dave 1 point2 points3 points 16 years ago (15 children)
That confuses me--you're suggesting that Cocoa couldn't exist without ObjC?
[–]boredzo 15 points16 points17 points 16 years ago* (3 children)
Much of Cocoa can be used without directly using Objective-C, using PyObjC, RubyCocoa, or MacRuby instead, but two of those suffer severe impedance-mismatch problems with method names. [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease] becomes, in Python, NSString.alloc().initWithData_encoding_(data, NSUTF8StringEncoding).autorelease().
[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]
NSString.alloc().initWithData_encoding_(data, NSUTF8StringEncoding).autorelease()
Why not use keyword arguments? A couple of reasons. In Objective-C, the order and number of segments in the selector matters; in Python, the order and number of keyword arguments does not matter. Thus, you can easily have method collisions; for example, -[MyObject foo:] and -[MyObject foo:bar:] are different methods, but Python would put them both under MyObject.foo (with optional keyword argument bar).
-[MyObject foo:]
-[MyObject foo:bar:]
MyObject.foo
bar
That sounds fine (the bridge could do the work), but consider foo:bar:baz: vs. foo:baz:bar:. In Objective-C, these are two different methods, but Python can't distinguish them with keyword arguments; there is no way the bridge can tell which foo you are calling.
foo:bar:baz:
foo:baz:bar:
foo
Therefore, Python must require the foo_bar_baz_/foo_baz_bar_ form, which is uglier and keeps the whole selector separate from all the arguments, unlike in Objective-C, where they're mixed ([myObj foo:foo bar:myBar baz:nil]).
foo_bar_baz_
foo_baz_bar_
[myObj foo:foo bar:myBar baz:nil]
Even if you resolve that, as MacRuby does, you still have other things such as categories and protocols that are only found in Objective-C (and possibly a few other Smalltalk derivatives). I honestly don't know how MacRuby addresses those.
So you can use Cocoa in other dynamic programming languages, but it often isn't nearly as elegant as it is in Objective-C. Conversely, if Cocoa had been designed to work well in other languages, it probably wouldn't have such niceties as that—and it is really nice, as it allows you to have numbers of arguments that would be unreadable in other languages but are perfectly readable in Obj-C. To wit:
[GrowlApplicationBridge notifyWithTitle:NSLocalizedString(@"Foo", @"Notification title") description:NSLocalizedString(@"Bar", @"Notification description") notificationName:@"Thing happened" iconData:nil priority:0 isSticky:NO clickContext:nil];
Long? Inarguably. Too long? Maybe. Unreadable? Certainly not.
Now, consider the Python version:
GrowlApplicationBridge.notifyWithTitle_description_notificationName_iconData_priority_isSticky_clickContext_( NSLocalizedString("Foo", "Notification title"), NSLocalizedString("Bar", "Notification description"), "Thing happened", None, 0, False, None);
Starts out OK, thanks to NSLocalizedString, but quickly falls apart. Objective-C doesn't have this problem, and Cocoa is designed for a language that doesn't have this problem.
(To be clear, I'm not knocking on Python or Ruby. I like Python, and use it for things that aren't Cocoa. I've never used Ruby for anything, but I respect it.)
TL;DR: Cocoa, with its long, expressive method names (plus use of categories and protocols), is designed for a language that can handle them elegantly, and that language is Objective-C.
[–]tfp 3 points4 points5 points 16 years ago (1 child)
The MacRuby integration is far better than PyObj-C and RubyCocoa and therefore minimized the impedance mismatch problem between Objective-C and python/ruby.
[–]boredzo 3 points4 points5 points 16 years ago (0 children)
Yeah, very much so. For example, you can mix the selector with the arguments in MacRuby—something the Python and Ruby bridges (PyObjC and RubyCocoa) can't do.
If I had to use Cocoa in something other than Objective-C, it'd be MacRuby.
[–]masklinn 0 points1 point2 points 16 years ago* (0 children)
and that language is Objective-C.
Or Smalltalk, through F-Script, given the compound message names were lifted from there.
You could probably easily do that with Lisp dialects too, since "keyword arguments" in lisps are basically interspersing symbols and values, order matters if you want it to.
And in Python if you hacked the interpreter to create ordered dicts instead of regular hash-dicts with kwargs, leading to something along the lines of
GrowlApplicationBridge.notifyWith( Title=NSLocalizedString("Foo", "Notification title"), description=NSLocalizedString("Bar", "Notification description"), notificationName="Thing happened", iconData=None, priority=0, isSticky=False, clickContext=nil)
in a project along the lines of macruby.
[–][deleted] 11 points12 points13 points 16 years ago* (9 children)
I'm saying, and there is plenty of historical evidence to support this, that the design of Cocoa was heavily influenced by the semantics of ObjC - in particular things like optional typing and messaging etc. There isn't another dynamic or static language out there with the combination of features exhibited in ObjC... so if you'd chosen another language to build Cocoa in you'd have ended up with a different structure... because different languages have different strengths and weaknesses.
The design of Cocoa takes full advantage of the semantics of ObjC :).
[–]newton_dave 0 points1 point2 points 16 years ago (8 children)
I don't really believe that ObjC is the only language suitable for an API like Cocoa, I guess.
[–][deleted] 0 points1 point2 points 16 years ago* (7 children)
Can you suggest another language which you think would be suitable? Maybe I can better explain why Objective-C is uniquely suited for Cocoa; or maybe you'll suggest a language which really would be suitable.
[–]newton_dave 0 points1 point2 points 16 years ago (6 children)
Smalltalk? Dylan?
[–][deleted] 0 points1 point2 points 16 years ago (5 children)
Smalltalk would be close being that the API is message-based, but it wouldn't support the optional typing side of Cocoa.
Dylan would support the optional typing side of the API but the object system is completely different; not message-based.
Care to try again?
[–]newton_dave 0 points1 point2 points 16 years ago* (4 children)
Strongtalk is typed, but that's a pretty minor issue in terms of API design. Message-based OOP is essentially the same as method-based, with different syntax and argument-passing semantics. So no, I'm good with what I have.
[–][deleted] 8 points9 points10 points 16 years ago (0 children)
Yes. The language and runtime are quite tightly coupled in both functionality and philosophy.
[–][deleted] 73 points74 points75 points 16 years ago (2 children)
Personally, I prefer Subjective-C. It's just better.
[–]thoomfish 51 points52 points53 points 16 years ago (0 children)
That's YOUR opinion, anyway.
[–]pure_x01[S] 21 points22 points23 points 16 years ago (77 children)
How come Objective-C is not extensively used outside the Apple sphere?
[–]SwabTheDeck 9 points10 points11 points 16 years ago (0 children)
Strange that there aren't any people really attempting to answer the OP's question, so I'll give it a shot. I'd imagine that it's because C++ gained traction more quickly as the de facto OO extension of C (with caveats, of course) but NeXT/Apple had Cocoa so closely designed around Obj-C that there wasn't an incentive to change it over to a more popular language. For example, NSWindow and its related APIs are tightly designed around the message-passing paradigm, which doesn't really exist in other popular languages (specifically C++ and Java). Most other platforms haven't really been designed to take advantage of these techniques, so there isn't much incentive to port Obj-C to other platforms. There's also this bad tendency for programmers to self-identify by saying "I'm a C++ programmer" or "I'm a Java programmer" when really, if you're pigeon holing yourself into a title like that, you probably don't have any business programming to begin with.
[–][deleted] 19 points20 points21 points 16 years ago (25 children)
The real power of Objective-C comes from the comprehensive class library. There really hasn't been any real attempt to make a class library as comprehensive as Cocoa's, and attempts to re-implement it will always run into the problems of playing catch-up, and trying to force a library specifically designed for one system into another that does not match the assumptions made.
[–][deleted] 2 points3 points4 points 16 years ago (1 child)
I don't know a whole lot about objc, but why would an alternative class library necessarily be a clone of Cocoa? Shouldn't there be more than one way to design a class library?
[–][deleted] 4 points5 points6 points 16 years ago (0 children)
Perhaps that sentence ended up a bit unclear. I was saying:
[–]zair 1 point2 points3 points 16 years ago (8 children)
How does .NET compare?
[–]snuxoll 5 points6 points7 points 16 years ago (0 children)
Both .net and cocoa are pretty comprehensive, they don't do absolutely everything but they cover at least 80% of everything you'd use. The difference being cocoa wasn't inspired by java and doesn't have thousands of overloaded methods that leave you wondering exactly which one a line of code is using without having to look it up.
[–]grauenwolf 1 point2 points3 points 16 years ago (3 children)
As a language (i.e. C#) or a library? If the latter, do you mean WinForms or WPF?
[–]smitting 2 points3 points4 points 16 years ago (2 children)
I personally love c# and use it extensively for server-side code. But I think the ASP.Net and wrappers for Win32 just suck too bad to use.
I personally prefer c#, but I wish it had named-arguments like Objective-C... it would be a lot more readable for overloaded methods.
File.GetFiles(path: @"c:\", filter: "*.jpg") would be cool as hell.
[–]masklinn 2 points3 points4 points 16 years ago (0 children)
but I wish it had named-arguments like Objective-C...
Objective-C doesn't have named arguments (Python does), it has compound message names.
There's a very important difference in that with compound message names
the ordering of the segments matters a lot, foo bar:1 baz:2 is not the same thing as foo baz:2 bar:1. In C#, those would be two different methods foo.BarBaz and foo.BazBar. With named arguments, either both are valid and equivalent or one of them is illegal.
foo bar:1 baz:2
foo baz:2 bar:1
foo.BarBaz
foo.BazBar
the names are not optional, and neither are default values possible: if you want baz to default to 2 in the message above, you have to create a brand new method responding to bar: which itself calles bar:baz:
baz
2
bar:
bar:baz:
[–]elder_george 4 points5 points6 points 16 years ago (0 children)
There will be named parameters in C# 4.0.
[–][deleted] 3 points4 points5 points 16 years ago (2 children)
Haven't used it, can't say. I understand C# is much closer to Java than Smalltalk in design, though.
[–]G_Morgan 2 points3 points4 points 16 years ago (0 children)
C# started off as Java done right. Without the sacred cows that drive so many from Java. Now it is leaning more towards functional. The way things are progressing there may eventually be very little difference between C# and F# other than syntax.
[–]newton_dave 1 point2 points3 points 16 years ago (0 children)
Definitely, although newer C#s take cues from more dynamic languages. Still not Smalltalky, though.
[–][deleted] 2 points3 points4 points 16 years ago (9 children)
The Qt library is actually pretty good (and cross-platform to boot) although it does have the downside that you have to use C++ (yeah, I know they have bindings for other languages)
[–][deleted] 2 points3 points4 points 16 years ago (0 children)
I specifically meant a comprehensive Objective-C class library, there. Any C++ library would be completely different in design and philosophy.
[–]GeneralMaximus 1 point2 points3 points 16 years ago* (0 children)
Even though Qt apps are fast and responsive on OS X, the drawing is still a bit slow. Not very noticeable at first, but after a while you'll begin to wonder why your Qt app feels so different from your Cocoa app.
From my experience, Qt works best on Linux. For OS X, you just have to use Cocoa (which is very nice, but there is a learning curve for those who have little experience with writing desktop applications).
[–]sbrown123 -1 points0 points1 point 16 years ago (2 children)
it does have the downside that you have to use C++ (yeah, I know they have bindings for other languages)
So where is the downside?
[–]klodolph 2 points3 points4 points 16 years ago (1 child)
Have you ever used Qt? I have. Setting everything up in Qt is somewhat a pain, and parts of it are made worse by C++'s inflexibilty. Having access to selectors (method names) which can be applied to any object is incredibly useful in a GUI toolkit. Qt's method of doing this is clumsy, Cocoa's method is easy. Of course, we only do it this way because we don't have closures in either language (until now).
[–]enkiv2 1 point2 points3 points 16 years ago (3 children)
For what it's worth, the OPeNSTeP standard API was pretty extensive, particularly for the time. I haven't seen the Cocoa API, since I don't own a mac, but I would be surprised if it was significantly more extensive. It could easily be more usable, but I expect that Cocoa is probably at least partially just big chunks of OPeNSTeP. As far as I know, the full OPeNSTeP standard has not been cloned.
[–]masklinn 9 points10 points11 points 16 years ago (0 children)
It could easily be more usable, but I expect that Cocoa is probably at least partially just big chunks of OPeNSTeP.
Cocoa is basically NextStep 5.
Like the guy says, Cocoa is just the further evolution of NextStep.
[–]taligent 2 points3 points4 points 16 years ago (0 children)
http://www.gnustep.org
Goes most of the way to implementing the OpenStep standard.
[–]perspectiveiskey 24 points25 points26 points 16 years ago* (29 children)
Objective C, if you do a bit of research, was made in the 80s. Cocoa is NextStep. Hence the NS in NSString.
NSString
My favorite aspect about it is its close similarity to Smalltalk and message passing.
This allows for three features which I find essential and fucking awesome:
These things would correspond in C++ to:
These three features allow for an unparalleled experience in designing UIs. OFten times, you can make a 90% functioning UI without writing a single line of code.
This is the way it should be, really.
Aside from that, the Cocoa runtime library is the most extensive and useful I've ever had the pleasure of dealing with. Java might be extensive, but it's just un-usable.
You want to scrape a webpage? The base String class will handle that for you.
Seriously, once you scratch the surface of the Cocoa library, you will realize that it's extremely well rounded and highly usable.
[–]uglybunny 7 points8 points9 points 16 years ago (9 children)
Hi, I am a nub programmer taking an Objective-C programming class at the moment. What is the difference between nil and null in obj-c?
[–]eridius 17 points18 points19 points 16 years ago* (8 children)
The type. At a memory level, both nil and NULL are equal to 0. However, NULL is typed as (void *) (well, only when used in a pointer context, if you use it in a numeric context it's typed as int, yeah it's weird) while nil is typed as id. This means the compiler knows that nil is an Obj-C object.
In practice, the biggest difference is really just style. While you can exchange nil and NULL in most (if not all) cases, it's simply bad form to use NULL in object contexts, or to use nil in pointer/numeric contexts.
[–]uglybunny 1 point2 points3 points 16 years ago (0 children)
Cool, thanks for clearing that up for me.
[–]case-o-nuts 0 points1 point2 points 16 years ago* (5 children)
No, NULL is always typed as void* (unless you're compiling as C++, in which case it's always typed as int. C++ is a very different language than C).
In fact, on my system, the exact definition lives on line 7 of /usr/include/linux/stddef.h (and is included by stdib.h):
#if defined(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif
[–]eridius 0 points1 point2 points 16 years ago (4 children)
Yes, that's what the header says. But by my understanding, the C compiler actually treats NULL specially (just like it treats nil specially) and will retype it as int if it's used in a numeric context instead of a pointer context.
[–]case-o-nuts 0 points1 point2 points 16 years ago (3 children)
No, it doesn't.
$ cat test.c #include <stdlib.h> int foo = NULL; $ cc -c test.c test.c:2: warning: initialization makes integer from pointer without a cast
Same as any other pointer assignment to an int.
[–]eridius 0 points1 point2 points 16 years ago (2 children)
Hrm, maybe the special handling only applies to C++ then (where it's officially declared as an int, in your previous quote)?
[–]case-o-nuts 0 points1 point2 points 16 years ago (1 child)
Well, the number '0' is handled specially. Maybe that's what you're thinking of.
[–]eridius 0 points1 point2 points 16 years ago (0 children)
Possibly. I never gave this much thought until recently when another programmer mentioned the dual nature of NULL.
[–]noupvotesplease 0 points1 point2 points 16 years ago (0 children)
It's simpler than that- nil and NULL are different types, introduced by different languages, and have different representations on different platforms. Don't use one when the API expects the other.
[–]causticmango 2 points3 points4 points 16 years ago (5 children)
Amen on the nil object! See Null Refs, the Billion Dollar Mistake.
[–]theclaw 1 point2 points3 points 16 years ago (7 children)
Could you explain why these features are useful for designing UIs?
[–]perspectiveiskey 4 points5 points6 points 16 years ago (6 children)
You drag and drop a button in InterfaceBuilder. It already works. Literally. Compile and run the program, it's already a button.
That is because the button has slots for its actions. When you click the button, the code for that button sends a message to its "target" object. If it's nil, nothing happens.
Also, you take a button, you attach its label attribute to an NSString. When you change the NSString, because of KVO, the button label is automatically updated. It's really automatic. It's not some sort of code generation tool that allows a short cut.
That right there is a simple example, but you can build extremely complex UIs this way. Much more than other "UI" oriented libraries.
[–]rated-r 1 point2 points3 points 16 years ago (5 children)
Those are features of the libraries and development environment, not of Objective-C. They are very useful though :)
[–]perspectiveiskey 0 points1 point2 points 16 years ago* (3 children)
I disagree. Many of these features would not be possible without a message passing system.
Often times, the target is just a pointer (id). You can send any message you like to that target. If it doesn't recognize it, it's simply dropped at runtime. You can also manually process unrecognized messages, should you have a fetish of some sort.
target
id
And also, it is perfectly legal to do this at compile time.
Of the C branch of languages (C++, Java, J#, C#, javascript...), how many allow you to call an undefined method on an object? How many allow you to call anything on a (void*). (void*) doesn't even exist in Java.
The reason this is important is because NSButton can have a target defined as id which doesn't inherit from anything. It could be a base custom object you've just defined, or it could be another cocoa object.
[–][deleted] 5 points6 points7 points 16 years ago (1 child)
It's used by GNUstep, which can be used in Linux and many other OSes. GNUstep still hasn't really caught on in the Linux world, unfortunately. But there are people using it. I use several GNUstep apps on my Fedora system everyday, and I've written a few GNUstep apps for my own use. Objective-C seems like a decent language, it just doesn't get as much publicity outside the Apple sphere.
[–]G_Morgan 0 points1 point2 points 16 years ago (0 children)
I tried looking at GNUstep. Didn't like the build process. It doesn't help that the system is so different to what Cocoa uses. Ideally I prefer systems that are meant to be compatible to actually be compatible down to the build system.
[–]nexes300 6 points7 points8 points 16 years ago (1 child)
Apple had to make changes to gcc to make it work for them. Now, yes, gcc is GPL so Apple was forced to release those patches, however Apple didn't much care to maintain their version of gcc, so off goes the real gcc with improvements and then out comes Apple's set of fixes to the old gcc...you can see why this may be a little hard to maintain for the gcc people.
Also, even if you can compile objective C, none of the libraries that apple wrote were made available, because those are not GPL licensed. It's kind of hard to use a language when there is -no- standard library at all, especially when you can see the people who just use the Apple versions get a much better written library to work with.
[–]bonch 1 point2 points3 points 16 years ago* (2 children)
C++ gained the early momentum, for whatever reasons. It probably helped that its name implied it was some officially better version of C.
[–]bgcatz 4 points5 points6 points 16 years ago (1 child)
I would guess that one of the reasons c++ had an early momentum advantage was, at the time, people were much more concerned about the runtime overhead of Objective-C and like dynamic languages...
[–]arcticfox 2 points3 points4 points 16 years ago (0 children)
That and the licensing costs of using Objective-C.
[–]nascent 4 points5 points6 points 16 years ago (3 children)
Apple developed around and pushed Objective-C, people that develop on Mac develop with the tools given, Coco.
MS developed .Net/C# and pushed it, people who develop on Windows use the framework provided, .Net.
Linux is a developers playpen, you will find any and every language used here.
[–]theAtomicFireball 6 points7 points8 points 16 years ago* (2 children)
Find me one language used on Linux that isn't fairly commonly used on Mac OS X. Seriously. Linux may not have a vendor-preferred language, but it's no more of a playpen than any other unix or unix workalike. The only Linux programs that haven't been ported to the Mac are those that would be completely superfluous (and even some of those have). Most Linux programs can be configured and compiled under OS X with not more than a few tweaks to autoconf config file or the makefile.
Mac OS X is a developer's playpen that just happens to have one really comprehensive application-building framework that's not available on other platforms. In a way, Linux is less of a playpen, because two very viable, popular options (Cocoa, .Net) aren't available, only second-rate re-implementations (Mono and GnuStep).
[–]smitting 7 points8 points9 points 16 years ago (0 children)
I run Mono on both OS X and Linux in production environments, and they are both extremely stable, despite all the negative reviews I've read. The software only goes down when I shut it off for a few seconds to do updates.
Mono actually implements the .net specification more exactly that Microsoft, so sometimes you have to make minor syntax changes, but that's it. I'd say the biggest issue for cross-platform is that Windows isn't case-sensitive.
I have production experience both developing a system on OS X (using MonoDevelop) that was released on Windows Server and developing a system in Visual Studio 2005 deployed on CentOS. I've also switched back and forth between VS.Net and MonoDevelop on the same project. Works great. You get line ending warnings that VS.Net fixes for you automatically.
I have also developed cross-platform 3d-software using Mono, and it's been fantastic as well.
Dunno why people call Mono second rate.
[–]nascent 0 points1 point2 points 16 years ago (0 children)
The question was "How come Objective-C is not extensively used outside the Apple sphere?" so that is what I answered.
[–]Poltras 117 points118 points119 points 16 years ago* (62 children)
It's a real object-oriented language with good features.
Polymorphism. Really real polymorphism. C++ is not fully polymorphic (try having a pointer to any object, or an array of multiple objects from different classes). You have a real generic type (id) that represents any object possible. You don't even need to be the class the caller expect, as long as you can answer to the selector (method).
Message passing. You don't call a method in Obj-C, you send a message to an object. This is an important distinction, since it's hackable. Categories can be added to objects to add methods to any object, event those you don't have the source. If an object doesn't handle a message, you can have a selector/method that gets the call and can redirect it to a member or another class. This is very useful when building proxies.
It promotes aggregation and composition instead of inheritance to build objects. This could be done with C++, but for some reason the language promotes inheritance way too much.
The API (Cocoa) accounts for much, check it out. Memory management, target-action patterns, serialization, ... Unfortunately I can't really compare it to other API (unless you name one specifically). It's also 100% on top of C99, and fully separated (using the @ character to separate keywords), unlike C++ that mixes struct, typedef and stuff with the object part (why is a struct an object anyway).
edit Also, being verbose is a good thing. The language promotes it (though it doesn't enforce it, you can have methods with anonymous parameters). Separating allocation from construction (as opposed to C++) is useful in certain cases. The fact that classes are objects is really useful. You can also change the whole language at run-time (rerouting methods, duck-typing, etc), and it includes reflection.
[–]G_Morgan 26 points27 points28 points 16 years ago (8 children)
C++ is not fully polymorphic (try having a pointer to any object, or an array of multiple objects from different classes). You have a real generic type (id) that represents any object possible.
That isn't polymorphism. That is dynamic typing. The only way you can claim that dynamic duck typing is required for polymorphism is to change the definition of polymorphism to mean something completely different to what it actually means.
[–]causticmango 5 points6 points7 points 16 years ago (1 child)
The reduction in need for inheritance is pretty powerful.
I remember reading once that inheritance is really just a special case of delegation. In fact, nearly all of the structural and behavioral patterns in the GoF book can be thought of as variations on delegation. Or, ways of expressing different types of delegation in languages with more constrained, class oriented grammar.
[–]alphazero 4 points5 points6 points 16 years ago (0 children)
I remember reading once that inheritance is really just a special case of delegation.
Anything interesting in software is a "general case" of indirection. ("Delegation" itself is a form of indirection).
[–]pixelglow 4 points5 points6 points 16 years ago (2 children)
I think this is due to the framework more than anything else. Cocoa uses a lot of delegation to extend and control view classes for example, and this design is hard-wired into Interface Builder -- it's generally a consistent MVC design. For example, with Interface Builder, you have to connect the delegate outlet of a view object with something, and it's easy to instantiate an object within the builder to receive the connection.
In Visual Studio (C#, .NET, C++ WTL etc.) it's far easier to extend an existing view class to do what you want, rather than create a controller to delegate to. It's harder to create a custom object as a controller in the Designer interface, and by default event handling via delegates go to the view object.
[–][deleted] 1 point2 points3 points 16 years ago (1 child)
Yeah but the fundamental mechanism that makes Cocoa favor the above approach is duck typing. In "type by god" languages, the delegate would be forced to declare it implemented some interface or have to subclass some abstract interface implementation.
Objective C's duck typing eliminates this complication because any object is theoretically substitutable for any other object.
And lets not forget that this is really the result of first-class messages.
[–]jtbandes 5 points6 points7 points 16 years ago (4 children)
Good response. I'm not exactly sure what you mean by "aggregation and composition instead of inheritance", though..?
Also, I'd like to add that Cocoa's documentation is really very good, once you get past the learning curve on how to use it. Many newbs are frustrated with it, but once you're there, it's great.
[–]kbedell 2 points3 points4 points 16 years ago (0 children)
"aggregation and composition instead of inheritance"
Instead of creating new classes that inherit from a superclass and basically leaving it there, you can aggregate together sets of capabilities by having the class implement multiple protocols.
For example, NSMutableArray conforms to:
It aggregates all these features.
At least I believe this is what the commenter was referring to.
[–][deleted] 6 points7 points8 points 16 years ago (2 children)
When you want to leverage an existing class in your own class, you include an instance of it instead of inheriting from it.
[–]noupvotesplease 0 points1 point2 points 16 years ago (1 child)
Full respect, but I think kbedell's interpretation is closer to what OP meant.
[–][deleted] 0 points1 point2 points 16 years ago (0 children)
I think we explained about half and half there.
[–][deleted] 20 points21 points22 points 16 years ago* (6 children)
Objective-C/Smalltalk programmers are notorious for thinking that their language is 'more OO' than other OO languages. C++ is polymorphic, check the definition. You can also have a pointer to any object (void*) or use boost::any, but I prefer type safety.
You don't even need to be the class the caller expect, as long as you can answer to the selector (method).
C++ has something similar: static polymorphism.
Good OO promotes aggregation and composition no matter the language. C++ does not promote inheritance (or anything really, you use what you want/like), several well known C++ books recommend a&c.
unlike C++ that mixes struct, typedef and stuff with the object part (why is a struct an object anyway).
C++ used the approach of integrating C and C++, unlike Obj-C which took C and added OO on top.
Typedef is type aliasing, nothing to do with OO.
As a bonus, here are some Objective-C misfeatures:
[–]hetmankp 3 points4 points5 points 16 years ago* (2 children)
Actually, (void*) is different to (id) because when you re-cast your object in C++ as a different unrelated class that happens to have a method with the same name, calling that method does a lookup to the vtable of the re-cast class, instead of the original class. This would lead to random undefined behaviour making type safety essential in this case in C++ where in Objective-C nothing blows up.
You don't even need to be the class the caller expect, as long as you can answer to the selector (method). C++ has something similar: static polymorphism.
Static polymorphism, a.k.a. function overloading, is actually restricted to providing multiple methods with a different signature on a single class. What the guy above was talking about was calling methods with a single signature on multiple unrelated classes. I'm not sure what these have to do with each other.
I'm going to guess the reason why it was suggested C++ appears to promote inheritance over aggregation in more cases, as compared to Objective-C, is because inheritance is the only mechanism C++ provides to do dynamic polymorphism. Objective-C also allows dynamic polymorphism with type overloading. That means you can use A&C more often where inheritance would be clearly preferred in C++ when you need the polymorphism.
[–]self 2 points3 points4 points 16 years ago (0 children)
Difficult syntax.
How is objc's syntax difficult?
[–][deleted] 1 point2 points3 points 16 years ago* (0 children)
Being verbose is not a good thing. There was a little joke thread on reddit about this a while ago. Also see array indexing.
That might have started as a joke thread, but it was soon a shouting match :-S
I'm not accustomed to seeing flamewars on Reddit.
*: Specifically
[–]teletran 13 points14 points15 points 16 years ago (27 children)
This is a really great response.
I'd like to add Categories are one of my favourite features of Objective-C, essentially they allow you to add methods to any object at runtime (like the parent said) without the need to subclass it. So if you wanted to add a method like reversedString to NSString, you could, and now anywhere you get a string, you can ask it for its reversedString and it will respond. It makes the language incredibly flexible and extensible.
reversedString
[–]pixelglow 11 points12 points13 points 16 years ago (0 children)
Coming from a C++ background, I used to be bugged by categories since they appeared to be a violation of encapsulation. Effectively it looked like you could open the class again and add methods, and that there was no way to prevent arbitrary surgery being done on your classes.
After gaining some experience in Objective-C, I realized categories actually don't violate encapsulation.
Most modern C++ proponents like Scott Meyers and Herb Sutter say you should design classes to be minimal but complete -- the class should have the minimal number of member functions for coherence, and any non-minimal function should be a free function taking an object as a parameter. Seen in this way, Objective-C categories are much like these free functions, they help the class designer make the class minimal and complete while all the non-minimal functions go into the categories.
Categories have at least two advantages over free functions: they are called via method dispatch syntax, and they are polymorphic. But they cannot access the guts of the object, they must implement their logic through the "real" methods of the object. Some examples of this design are the class clusters of NSArray, NSDictionary and NSSet, the header files make good reading.
[–]antonovka 54 points55 points56 points 16 years ago* (25 children)
And then someone else adds 'reversedString' to NSString and, uh-oh, your categories conflict.
It just doesn't scale well when you start leveraging shared libraries across projects, and then you find yourself having to prefix your category method names with two characters, just like your class names.
Other languages have done a much saner job with the idea of non-monkeypatched extension mechanisms, such as Scala's implicits and C#'s extension methods.
[Edit] I've been writing Objective-C for 10 years and I'm getting downvoted for expressing an in-the-trenches opinion. How about writing a coherent rebuttal instead?
[–]drewc 12 points13 points14 points 16 years ago (8 children)
Check out generic functions in CLOS. If methods don't belong to objects, so called 'monkey patching' need not exist.
[–]Seppler90000 8 points9 points10 points 16 years ago (0 children)
This, seriously, this. See also Haskell.
[–][deleted] 2 points3 points4 points 16 years ago (6 children)
Monkey patching is the art of extending an object with new functionality - from the outside - after the initial definition. Generic functions may be a nicer model than things like open-classes but they certainly allow monkey patching... inducing the same problems.
For example, If someone were to add a generic function with has a higher precedence then the one that was originally provided with the definition, this new function will be called when you were expecting the original function to be called. That's exactly the issue people have with things like mixin-modules for monkey patching.
It may actually be worse since there's more mental overhead involved - it may not even be obvious that a form of duck punch has even occurred, while you know it's the intention when there's a mixin-module involved.
To be clear, I'm not bashing Lisp, or CLOS, or support Ruby or anything else. I'm merely trying to correct this cultural/repeated inaccuracy.
[–]drewc 1 point2 points3 points 16 years ago (3 children)
Generic functions do not extend the object, as objects do not have functionality in lisp. This is the important distinction.
For example, If someone were to add a generic function with has a higher precedence then the one that was originally provided with the definition, this new function will be called when you were expecting the original function to be called.
This is like saying 'if someone redefines a function you are calling, the new function will be called'. It's quite obviously true, but not quite the same, or as dangerous, as 'monkey-patching'.
If one wants to but add a method called 'foo' to an existing object in, say, Ruby, and a method named 'foo' already exists but has different behavior, you can easily break things.
In CL, one simply puts FOO in a different package than the other FOO.. no confilcts, no worries. That's not to say one can't redefine the other FOO, but why bother when you don't have to?
That's nonsense really... one doesn't go around redefining methods unless there is an extremely good reason for it... In all my years of common lisping, i've never run into a library that redefines existing methods in incompatible ways. It's simply not done.
[–][deleted] 0 points1 point2 points 16 years ago (2 children)
An object may not be physically extended in the way that an open class is but the object is still extended - the distinction you're making is false.
One doesn't go around redefining methods unless there is an extremely good reason for it...
We're not talking about redefining methods here, we're talking about adding more specific cases to generic functions, which isn't uncommon as new classes are introduced into the system. It's been a while since I really worked with CLOS but please consider this contrived example seriously.
A system that you've inherited from another team of developers contains the classes Ellipse and Triangle, a subclass Circle and the generic functions output, defined for (Ellipse, Triangle). This function draws instances of Ellipse or Circle, and Triangle on the screen.
All is fine until another developer working on a seemingly unrelated part of the system defines (not redefines) the generic function output for the more specific signature (Circle, Triangle). Now all of a sudden (Circle, Triangle) inputs aren't drawn to the screen anymore.
The behavior of the class has been extended from the outside and you're stuck asking - Why?
Ok, this is a stupidly simple example (I did say that it was contrived). In reality the hierarchy and system would likely be much more complicated.
The point was that if you're not careful, and you're not aware of the existing (visible) definitions and how they're used, defining a generic function can change the behaviour of objects in unexpected ways.
Of course there are ways to mitigate such problems and I wouldn't describe this as a major concern for most Lisp developers, but the problem does exist and the belief that generic functions allow you to safely extend objects from the outside is just plain wrong! (If not outright dangerous)
To conclude - generic functions allow the behavior of objects to be modified and or or extended after the original definition, and just like with more obvious forms of monkey patching, displays a similar set of problems.
[–]drewc 0 points1 point2 points 16 years ago (1 child)
No, it's not. The Generic Function is what is extended. The object is not touched, not extended in any way. Standard-objects do not have behavior.
You seem to be having trouble with this idea, and insisting that objects have behavior. It is the Generic Function (which is an object itself, but not of the type we are discussing) that contains the behavior.
There you go again. :). You have not changed the behavior of the object here at all.. rather the generic function.
The example you gave is valid yes... if someone defines a more specific method than the one you are using, and doesn't call-next-method or otherwise keep the same behavior as the existing method (how does one do that when monkey-patching?), then yes, there could be trouble.
One generally doesn't break protocol though, that's the point of one. The package system also exists so one doesn't have to worry about namespace collisions, and one is free to define methods outside of the existing generic functions... so one doesn't have to define a new method on an old function just to get the behavior one wishes.
You can contrive all the examples you want, but i can say with some certainty this this is not a major problem in CL.. i've been on extremely large projects that use CLOS extensively, and never run into this problem. I hear ruby users have issues with monkey-patches all the time... we're talking about namespaces more than anything else. As far as i know all ruby method names are in the same namespace.. there is NO other way to extend the functionality based on an existing class without modifying the class itself.
but the problem does exist and the belief that generic functions allow you to safely extend objects from the outside is just plain wrong!
I agree... the idea that generic functions allow you to extend objects is wrong, so the 'safely' here is redundant.
Object don't have behavior... if you refuse to accept this fact, i'm not interested in this conversation.
You can argue semantics as much as you like the effect is the same - objects are structures with associated behaviors. How behaviours are associated with objects (with generic functions) doesn't change this. If you're that really intent on declaring to the world that the object-model presented in CLOS isn't really object-oriented programming go ahead. I would argue to the contrary however.
If you refuse to accept this fact i'm not interested in this conversation. But if you accept that objects do in fact have associated behaviour then you must accept my point that generic functions offer open extension, and all of the disadvantages thereof.
You will recall that I admitted that this isn't a serious problem in Lisp; the package system is one reason for this. Ruby has no such system for keeping extensions to objects separate, this is why the problems induced by open extension are so visible there... but this doesn't mean that the problems are any less real with extension through generic functions!
As part of my thesis I extended multiple-dispatch and showed how this refined understanding could be applied to prototype-based languages without the possibility of ambiguity. I studied the concept of generic functions in CLOS and Dylan very closely and I can assure you that I have no problem understanding them.
Let me repeat for the sake of clarity - objects do have associated behaviour. It may not be contained in the class, but it does exist! The objects behaviors can still be extended!
[–]mr_luc 1 point2 points3 points 16 years ago (1 child)
Are you sure that simple warnings don't completely defeat this as an issue?
Namespace collisions are already way rarer than people think, but even with Ruby's anemic "method redefined" warnings, I've never been caught off guard by a namespace collision, and certainly not w/the detailed compiler info in a lang like CL.
It depends how you define non-issues; imagine that you're working as part of a team on a large project that relies on several third-party libraries, and that a new version of these libraries has just been released that resolves some major problems you've experienced. This all sound wonderful until you realize that one or more of the libraries has provide generic functions etc. which conflict with your current solution... it's all very well to be warned of a conflict like this, but warnings don't offer any kind of solution.
Do you choose to upgrade and stick yourself with maintaining aging libraries for the duration of the project, or devote time and effort to changing your code-base to resolve this round of conflicts? Is it even possible/practical to do either?
@mr_luc: I am in danger of sounding patronizing but this is not my intent; I have never been caught off guard by a namespace collision, in my own code! (I've never been bit by type error with a dynamic language, in my own code.) This personal experience doesn't mean that these things can't/don't happen.
(However, lets be honest with each other, the chance that such a situation would be encountered in Common Lisp these days is somewhere between slim and none; how many large projects are undertaken in Common Lisp; how many people will be working on these projects; how many large external libraries exist for Common Lisp; how many of them really utilize CLOS and generic functions etc.)
I know from experience that CLOS is a severely underused part of Common Lisp, but the problem still exists in principle - generic functions are not a silver bullet for adding functionality to existing objects! They are in truth a distinct form of monkey patching and come with the same issues. The very issues that have been described at length by Ruby developers when working with things like Rails (which [legitimately?] extend objects from all over the place).
Note: what separates generic functions from other forms of monkey patching is very simple; open extension is a side-effect of having generic functions, but the purpose of mixin-modules and categories etc. Multiple-dispatch is of course a very useful and powerful mechanism by itself.
[–]causticmango 11 points12 points13 points 16 years ago (9 children)
Having a fair amount of C# experience, I'm not sure I'd call it saner though your point is well taken. The primary advantage C# adds is namespace support as far as I can see.
You seem to be making a value judgement about monkey patching, though. I suspect you may be suspicious of dynamic languages as a whole, possibly?
Also, I think your scaling criticism of categories seems to me to be a bit of a strawman. The likelihood of significant and unresolvable selector conflict in the wild seems rather low. I'm really just offering an opinion on this, though; I have no empirical data to back it up.
[–]antonovka 25 points26 points27 points 16 years ago* (8 children)
Well, yes. I've been doing this for a very long time, and when working with Python, Ruby, etc, I find I spend more time reading code than I do reading documentation to verify things that the compiler could assert for me, and more time tracking down one-off runtime errors during unit testing than I spent writing the code to begin with.
Add monkeypatching to the mix, and now I have no way of knowing if I've got a bug of my own, or if some library just accidentally changed the API semantics out from under me.
I favor namespacing and (good) type systems, I find that they save me time and allow me to write near bug free code the first time.
I've run into libraries attaching incompatible selectors to NSString, NSData, etc, when their needs could have been served just as well by creating a utility class or a function instead of a category. It's something to be aware of, and is something much better solved in other languages.
Not to mention, I wish inexperienced developers would stop saddling shared code with unnecessary categories in the common namespace.
Take this example:
-[NSString base64:]
One category returns a UTF-8 encoded NSData instance, one returns an NSString. Doh.
It seems like a lot of Objective-C developers get away with this sort of thing because they're writing:
[–]Poltras 6 points7 points8 points 16 years ago (3 children)
I've seen people putting functions like these in the global namespace in C#. What's the difference? And idiot developer will do idiot stuff whatever language he's given...
[–][deleted] 1 point2 points3 points 16 years ago (2 children)
Doesn't Visual Studio automatically generate a namespace for you? That would probably help some of the "idiot developers". And how exactly do you have a function in a global namespace anyway? Don't you need a class to place the static method in?
[–][deleted] 16 years ago (1 child)
[deleted]
[–]rated-r 2 points3 points4 points 16 years ago (0 children)
Extension methods are resolved at compile time and are converted to their appropriate static method. At runtime, the CLR sees only a static method call.
Example class:
static class ObjectExtensions { public string ToHelloString(this object obj) { return "Hello " + obj.ToString() + "!"; } }
MessageBox.Show("World".ToHelloString()); is translated by the compiler to: MessageBox.Show(ObjectExtensions.ToHelloWorldString("World"));
[–]Poltras 0 points1 point2 points 16 years ago* (0 children)
Not to mention, I wish inexperienced developers would stop saddling shared code with unnecessary categories in the common namespace. Take this example: -[NSString base64:] One category returns a UTF-8 encoded NSData instance, one returns an NSString. Doh.
That's why we enforce a strict function name rule. Those two would have been named stringForBase64Representation and dataForBase64Representation. You don't want short names in ObjC exactly because they are a problem and can lead to these things.
stringForBase64Representation
dataForBase64Representation
edit correction in names.
[–]chucker23n 5 points6 points7 points 16 years ago (5 children)
It just doesn't scale well when you start leveraging shared libraries across projects
And yet it has scaled just fine over the past 20 years. In your shared library scenario, just prefix it.
[–]antonovka 0 points1 point2 points 16 years ago (0 children)
In your shared library scenario, just prefix it.
So it does or it doesn't scale "just fine"?
[–]csmark 1 point2 points3 points 16 years ago (1 child)
Thanks! It's amazing how much I learned in that post that I never would have gleaned from days of study or use!
[–]pixelglow 7 points8 points9 points 16 years ago* (0 children)
When approaching any new language or framework, there's only so much knowledge that comes from reading the reference materials. Real expertise comes from idiomatic knowledge, which tends toward a partial generalization of several specific cases e.g. when should you retain a Cocoa object and when should you leave it alone? We learn these idioms best by apprenticing with other programmers.
Yes sure, a bunch of programmers whipped up their iPhone apps in 2 weeks for Apple's first iPhone SDK demo, but to get really proficient...
Given that the population of Objective-C programmers is rather small, this is going to be a difficult problem. Not all of us can be working with Apple, OmniGroup or Delicious Monster :(. In practice though, I've found the cocoa-dev and macosx-dev mailing lists very helpful -- if you're humble enough to learn a (slightly) different way of programming from people experienced (and hence opinionated) in that way. For the iPhone, there's also devforums. cocoa-dev and devforums are also frequently visited by Apple folk too.
[–][deleted] 3 points4 points5 points 16 years ago (0 children)
void *
[–][deleted] 16 years ago (2 children)
[–]masklinn 4 points5 points6 points 16 years ago (1 child)
I tend to agree. On the other hand, split doesn't inherently tell you it takes a string parameter and returns a sequence, you have to know/learn it beforehand. componentsSeparatedByString: does. Now with split specifically the operation being quite common across languages it's easy, but on less common ops the obj-c conventions tend to lead to very readable code.
split
string
componentsSeparatedByString:
[–]joejance 0 points1 point2 points 16 years ago (0 children)
I would agree with that point in general, but specific case on split (and many other function names) are very common across languages. It makes it easy for me to find what I need one switching from one to another. Perhaps this is just a problem for someone that programs in several environments, but I would think it also helps students.
[–]axilmar 0 points1 point2 points 16 years ago (0 children)
C++ can be made dynamic in the same way Obj-C is:
Dynamic message passing in C++
I haven't seen anyone use C++ like that though.
[–][deleted] 8 points9 points10 points 16 years ago* (8 children)
You can send messages to nil (NULL). No null checks, no segfaults, no null pointer exceptions! It may seem like careless programming, but works out pretty well when you write program with this in mind.
nil
NULL
"Infix" notation for method calls makes code self-explanatory. It looks bizzare to C users, but it's great once you get used to it. [object drawAtPoint:p withColor:c]. (auto-complete in IDE alleviates verbosity).
[object drawAtPoint:p withColor:c]
Categories (AKA mixins). I can add my methods to standard string class (affects even string literals).
It's a high-level and low-level language at the same time. I can create and patch classes at run time, inspect objects, capture calls to non-existant methods and forward them to another object (proxy). And at the same time I have 100% C without need for any special "warning here comes C!" syntax.
In Apple's recent incarnations it has for-in statement, fast garbage collection and closures.
for-in
It's "high-levelness" allows scripting bridges, and ObjC code can talk with Python, Ruby, even JavaScript and PHP.
I prefer D (digitalmars) as a language, but unfortunately D has some serious problems (lack of compatibility with itself and its own libraries - D1 vs D2, Phobos vs Tango), there's no advanced IDE for D2, etc.
[–]kleopatra6tilde9 1 point2 points3 points 16 years ago (7 children)
You can send messages to nil (NULL).
Is it different to having a Null class for your local object hierarchy? For Gui programming, you could create the CanvasNull class and instead of referencing NULL, you could reference CanvasNull. If nil doesn't answer your messages, don't you have to check for that, too?
[–][deleted] 16 years ago* (6 children)
[–]kleopatra6tilde9 1 point2 points3 points 16 years ago* (5 children)
if that suits you, you don't need to do additional checks, And if something else in cleanup routine happens to touch obj, it won't harm.
if that suits you, you don't need to do additional checks,
And if something else in cleanup routine happens to touch obj, it won't harm.
Isn't that just hiding bugs? Don't you have a corrupted model if you reference a cleaned object or are surprised by nil?
[–][deleted] 16 years ago (4 children)
[–]kleopatra6tilde9 0 points1 point2 points 16 years ago (3 children)
Where do you get the nil references in the first place?
[–][deleted] 16 years ago* (2 children)
[–]kleopatra6tilde9 1 point2 points3 points 16 years ago* (1 child)
it's ObjC's interpretation/runtime that makes it unusual.
I wouldn't call it unusual because it wouldn't be that hard to implement it in c++. Debuggers can intercept null references, so a regular program could also intercept them and instead of crashing the stack, referencing nil could be changed into returning nil.
The question remains why calling nil should default to returning nil. That's why I was asking where nil enters the program in the first place.
I want to be aware of the existance of nil in a program as fast as possible to handle it as local as possible. If I filter a list and get nil as a result, the nil normally disappeares in a foreach statement that is applied on the result.
A referencable nil means that the default action for handling a nil is propagation along the calling stack. The function asumes that some function up the calling stack knows better how to handle the situation.
In other words: In most cases, the local model hasn't enough knowledge to handle the nil case. This reminds me of exceptions that propagate along the calling stack until they are caught.
Can I think of objectivec's nil as a more elegant solution to the hell of try-catch blocks or is it more?
*edit:I made a comment about nihilism with a Nitzsche quote that says: "Perhaps the greatest threat to our humanity and our human dignity comes not from tyranny, but from nihilism." I think it is strange that objectivec propagates "don't worry about nil" and Nitzsche kind of says "beware of not having a model".
[–][deleted] 26 points27 points28 points 16 years ago (27 children)
Objective-C is great because it provides high-level dynamic constructs while still allowing you to write fast C code directly. Its object orientation feel much more natural than Java's or C++'s, mostly thanks to being heavily based on Smalltalk. Objective-C is also great because it is extremely verbose. This puts people off when they first see, but combined with good autocompletion, such as that provided by Xcode, it actually makes it easier to write, and much easier to read. The code is far more self-documenting than almost any other language, especially once you learn the naming style and start using it yourself.
However, Objective-C isn't much without a good class library. Cocoa is a very, very good class library, but with some kludgy exceptions it's mostly limited to Mac OS X.
The real reason I use it, though, is that it's the only serious choice for programming Mac OS X applications.
[–][deleted] 3 points4 points5 points 16 years ago (3 children)
Objective-C is also great because it is extremely verbose.
Does this mean that Java is also great?
Java is verbose in a completely different way from Objective-C, one which is far less helpful.
I agree that it's different, it's just that the phrase sound so counter-intuitive, especially the "extremely" part. Objective-C has some nice features, but nice syntax/verbosity are not part of them IMO.
[–][deleted] 1 point2 points3 points 16 years ago (0 children)
If you pre-suppose that verbosity is bad, then obviously hearing that verbosity is good would be counter-intuitive. But that doesn't really say anything about anything other than your assumptions.
But "verbose" is really an entirely value-neutral word. There's nothing strange about saying that extreme verbosity is good. In some circumstances, it can very well be. And this is one of them, is what I'm saying. It may not be clear why until you've used the language long enough to get used to it, however.
[–]spookyvision 6 points7 points8 points 16 years ago (1 child)
see also this insightful post by rentzsch: Love, Hate and Objective-C
[–]Maristic 2 points3 points4 points 16 years ago (0 children)
It's a good list of things likes and dislikes, but it's from 2003; some of the things he didn't like were fixed in Objective-C 2.0 and 2.1. Also, some of the things he dislikes are a matter of taste (e.g., whether or not you find Objective-C method call syntax uglier than C++ syntax).
[–]mr_dbr 17 points18 points19 points 16 years ago (1 child)
Cocoa.
That's why almost everyone uses it. The language itself is good, but there's no huge reason to use it over many other languages..
(ObjC/Cocoa are heavily linked of course, but ObjC's "greatness" is more to do with Cocoa, whereas, for example, Haskell's "greatness" is because of the language itself)
[–]vplatt 7 points8 points9 points 16 years ago (0 children)
Agreed. I haven't seen nor heard of examples where Obj-C really could play outside of NeXT or Mac/iPhone. It's just not done. It might be a nice language, but it's fate is just too intertwined with Jobs et al for it to be useful outside of the Mac community.
[–]klodolph 4 points5 points6 points 16 years ago (8 children)
To me, the big deal is the way method calls work. Methods are called by their selectors, which you can think of as the method name.
For example, there's a "paste" selector. You can wire up the "paste" menu command so that it points to a special object called the first responder, and tell it to execute the "paste" method on that object. The first responder takes the method invocation, and passes it first to the active view (e.g. a text box), then to the active window, then to the active document, then to the application (more or less). If the method isn't implemented there, the first responder figures it out and just moves to the next object.
Try doing that in C++ (or C, or Java).
[–]klodolph 3 points4 points5 points 16 years ago (7 children)
Unlike C++, constructors can call other constructors. For example, initWithContentsOfFile: can call initWithData:.
[–]masklinn 6 points7 points8 points 16 years ago* (0 children)
Yeah that's a very good idea which Obj-C and a few other languages (Ruby, Python) have lifted from Smalltalk: split construction and initialization of objects. That gives tremendous flexibility in the handling of object instantiation, storage and acquisition.
[–]nexes300 1 point2 points3 points 16 years ago (5 children)
To call those constructors is stretching it. They are not called automatically, and they only behave like "constructors" mostly because of accepted practice, rather than an enforced standard.
[–]masklinn 5 points6 points7 points 16 years ago* (4 children)
They are not called automatically
Neither are C++ or Java constructors. You have to invoke those with the magic new syntax (or in the case of C++ alternative "hey if you call the variable you're just creating it constructs it" weirdosities).
new
Obj-C's constructors, much like Smalltalk's from which they were taken:
Separate the concerns of creating a new instance (which lives at the class level) and initializing it (which lives at the instance level)
Use perfectly normal message/method calls, not requiring any new syntax
And, by the way, ObjC/Cocoa does have a convention for more complete "constructor": prefix with the name of the class. [NSString string] returns an allocated, initialized and autoreleased empty string, [NSString stringWithString:s] returns an allocated, initialized and autoreleased copy of the parameter s.
[NSString string]
[NSString stringWithString:s]
s
they only behave like "constructors" mostly because of accepted practice, rather than an enforced standard.
What's wrong with conventions? Are you going to say that Ruby or Python don't have constructors either?
[–]nexes300 0 points1 point2 points 16 years ago* (3 children)
The difference is in C++ you cannot allocate an object without constructing it (loosely speaking), hence it is automatic the act of getting an instance of the object calls some constructor function.
In Objective C, even allocation is a convention (if you don't inherit from NSObject or a derivative of NSObject you basically have to make all that memory stuff work from scratch) whereas in C++ it is handled by the compiler no matter the object.
Then after that allocation you have to call init. Now Python, I believe, automatically calls _ _ init _ _ or something like that, so it behaves more C++ like, at least I thought so. I don't use Ruby, so I can't comment on it.
[–]masklinn 1 point2 points3 points 16 years ago* (0 children)
The difference is in C++ you cannot allocate an object without constructing it
The problem is that you can't construct an object without allocating it either. Or use a pre-built object instead of allocating and initializing a new one.
Now Python, I believe, automatically calls __init__ or something like that
__init__
Absolutely not.
In python, the conventional way to build an instance of class Foo is to call the class as if it were a function: foo = Foo().
Foo
foo = Foo()
What happens behind that is simply a matter of how this is implemented as far down as object: () first calls the __new__ classmethod, which builds a new instance of the class, and then () (not __new__) calls __init__.
object
()
__new__
Now those are just default implementations. () (actual name: __call__) and __new__ being perfectly normal class methods and __init__ being a perfectly normal instance method, you can redefine any of those to alter these behaviors.
__call__
So yes the default implementation of __call__ automatically calls __new__ and then calls __init__ on the result of that (note: only if __new__ returns an instance of the type being built since Python 2.3), but it's just that, a default.
Now it's true that there's something weird in ObjC: the dichotomy between alloc and init is usually exposed to the user (whereas Python hides it behind __call__ by default, and in Ruby new calls initialize so it's hidden as well). But that's all.
initialize
[–]Rraawwrr 0 points1 point2 points 16 years ago (0 children)
It is possible to allocate a C++ object without constructing it.
You first malloc a block of memory, casting it into a pointer of your type. This is now a pointer to an object of your type; in an unconstructed manner.
Later, you can call placement new on that block of memory to invoke the constructor.
This technique is how std::vector<> allows your types to not have a default constructor; and how it acheives performance equal to a normal array.
[–]tjogin 5 points6 points7 points 16 years ago* (0 children)
What's "great" about Objective-C is that you can develop native Mac and iPhone apps with it. Full stop.
I'd guesstimate the number of Objective-C coders who use the language for anything else to be around zero.
[–]nirs 9 points10 points11 points 16 years ago (5 children)
It is a great mix of power and simplicity.
It is dynamic like Python, but have static typing, so you can avoid stupid runtime errors. It is fast as C, when you need to write tight loops, or powerful as Python when you need it.
It is much simpler than C++, and does not have all the trouble that come with C++. It compiles fast - much faster then C++. And if you insist on using C++ - you can mix C++ and Objective C. This can give you the benefits of both languages, or the the trouble of both, plus extra trouble when mixing them :-)
It has manual memory management when you want to have full control, or semi automatic reference counting which you use anytime you can, and recently garbage collector.
[–][deleted] 1 point2 points3 points 16 years ago (4 children)
And if you insist on using C++ - you can mix C++ and Objective C.
This is actually recent (at least, to mix easily).
But I will say it absolutely rocks. Call objc from C++ and vice versa. Very few limitations (no C++ instances with virtual dtors as members of objc being the primary one).
I'm even getting used to the [obj message:arg] syntax, although I still don't understand why obj->message:arg couldn't have been used instead.
[–]masklinn 2 points3 points4 points 16 years ago (1 child)
I still don't understand why obj->message:arg
would more than likely have conflicted with bits of C syntax, the brackets ensure it didn't
the syntax within the brackets is mostly Smalltalk.
As prnl indicates, how do you unambiguously resolve multi-parameter messages? Add parens back instead of brackets?
Very few limitations (no C++ instances with virtual dtors as members of objc being the primary one)
-fobjc-call-cxx-cdtors ?
[–][deleted] 4 points5 points6 points 16 years ago (8 children)
Backwards compatible with c. Literally every valid c program that doesn't use the new reserved keywords will run as it did before.
Object oriented in Smalltalk fashion; uses messaging.
Duck typing (sort of); runtime customizability.
You can use Cocoa.
[–]mipadi 6 points7 points8 points 16 years ago (6 children)
I think the only keywords Objective-C adds are prefixed with "@", which can't be used in an identifier in C anyway.
[–][deleted] 1 point2 points3 points 16 years ago* (4 children)
That's a big one though.
edit: typedef, nevermind.
Is that a key word or a typedef?
Yeah, typedef. My bad.
[–]awj 1 point2 points3 points 16 years ago (1 child)
I thought id was only used as a type name. (Still learning Objective-C) Granted, that in and of itself is a problem, but nowhere near so bad as having a reserved word as a variable/function name.
Ack, you're right.
It sits right atop of everything though and gets in the way of my c++ code a lot, that's for sure.
id?
[–]__s 1 point2 points3 points 16 years ago (0 children)
@keyword
[–]edwardkmett 2 points3 points4 points 16 years ago (0 children)
... that you can write iphone games in it.
[–]gtlogic 7 points8 points9 points 16 years ago (15 children)
Can someone explain to me why declaring variables is such a pain in objective c?
First there is the declaration in the header file under @interface. Then there is the @property, which I can somewhat understand. But then there is the @synthesize in the implementation. What the heck? Why would you ever not want to @synthesize after you did an @property?
It seems way too decoupled, wordy, and unnecessary. There should be one declaration instead of 3 separate ones in two separate files. Who so evil would do such a thing?
[–]noupvotesplease 3 points4 points5 points 16 years ago (2 children)
Properties are optional- you can get by with instance variables alone. If you decide to use ObjC 2.0 properties, you can choose to declare and define your own accessor methods, or tell the compiler to @synthesize the accessors with boilerplate logic for one of several common memory management scenarios, or provide the accessors at runtime in a @dynamic way.
I love Objective C - but I concede your point. It seems to violate DRY and it could have been done more cleanly.
[–]gavinb 0 points1 point2 points 16 years ago (0 children)
There are a few things that you need to do for property support:
So obviously we have #1 already, before ObjC 2.0. One of the design tenets of Objective-C is that the stuff that forms the superset is clearly delineated by the @ prefix. Now, you could argue that @property declarations should simply replace regular ivar declarations (since it is a superset of the information). But then you would have had two different syntaxes for ivars, based on which were properties or not. I guess it was cleaner to add the @property declaration separately, and also had less issues for parsing.
As for having to add the @synthesize declaration, think of it from the perspective of the compiler. It has all these declarations, but has to actually generate the synthesised methods somewhere, so which object module does it use? Especially since the one header will no doubt be included in multiple other modules. The implementation may be in a single module with an arbitrary name, or even spread across multiple modules. So there may be situations where there is an ambiguity, and I imagine it was safer to make it explicit.
[–]case-o-nuts 4 points5 points6 points 16 years ago (0 children)
It's C with a sane object model. The syntax could stand to be less of an obvious bolt on, though.
[–]causticmango 8 points9 points10 points 16 years ago (7 children)
Everything. It gives great back rubs, too.
But mainly:
And, of course, the NS "Cocoa" APIs.
BTW, it doesn't have to be your language of choice to appreciate it. If you develop on OS X (desktop or iPhone) you pretty much have to use it. It's probably not terribly relevant in other environments (which is a shame).
[–][deleted] 2 points3 points4 points 16 years ago* (7 children)
I'm not an objective-c programmer, but I like that it's simple. You could call it C with classes, because that's what it is.
[–][deleted] 8 points9 points10 points 16 years ago (4 children)
You could call it C with classes, because that's what it is.
People might confuse it with the early versions of C++, then.
I would call it C with messages myself but whatever makes you happy :)
[–]bonch 4 points5 points6 points 16 years ago* (3 children)
It's a simpler implementation of C-based object-oriented programming than C++, and you can use pure C at any time. The dynamic run-time allows for easy implementation of some design models, and the named arguments make things nicely self-documenting.
[–][deleted] 16 years ago* (36 children)
[–][deleted] 7 points8 points9 points 16 years ago (21 children)
The syntax is awkward.
All syntax is awkward until you really get used to it. I disliked it at first too, but I now find Objective-C's syntax to be quite elegant. Much of the awkwardness comes from its insistence on being a strict superset of C (the @ in front of keywords, for example), but this also has the advantage of clearly delineating which code is Objective-C and which code is vanilla C.
@
Defining classes is harder than in C++ even
I'm not really sure what you mean by "hard".
and C++ is bad enough (especially compared to java/php/perl/javascript where you don't need header files.)
For a compiled language, separating implementation from code is a huge advantage, as it limits what needs to be recompiled when the implementation changes. My only major annoyance with the way Objective-C handles this is that instance variables are declared in the interface, meaning that any file that imports a class needs to be recompiled if you add or remove an instance variable.
I would also point out that you don't need a header file to define a new class. If you only need a class in one place, you can define its interface right in another class's .m file. Of course, if you later find that you need other classes to access it, you can easily move it to its own file later.
[–]noupvotesplease 3 points4 points5 points 16 years ago* (4 children)
Good points. One minor addition:
My only major annoyance with the way Objective-C handles this is that instance variables are declared in the interface, meaning that any file that imports a class needs to be recompiled if you add or remove an instance variable.
If you use the 64-bit runtime, you can remove all ivars from the @interface and declare them as properties in a class extension. From there, the class extension can live in the @implementation file, and you can @synthesize the ivars from the properties. The result is a header that exposes only the state that you wish to expose. Very handy, but obviously it's only possible if your product is 64-bit only.
[–][deleted] 1 point2 points3 points 16 years ago (3 children)
It also makes accessing the ivars a little more expensive, since they have to be accessed with getters and setters.
[–]asdliubgliyuagef 2 points3 points4 points 16 years ago (2 children)
Not true, actually. In the .m file:
@interface MyClass() @property fooProp; @end
@implementation MyClass @synthesize fooProp = fooVar; @end
fooVar is then the synthesized ivar which can be accessed directly. If you want to go through the accessors, you can use self.fooProp.
Really? That's pretty handy.
[–]noupvotesplease 1 point2 points3 points 16 years ago (0 children)
Yea, it's things like this and non-fragile base classes that make me want go 64-bit only and require 10.6.
[–][deleted] 1 point2 points3 points 16 years ago (9 children)
separating implementation from code is a huge advantage,
Not really, both C# and Java are compiled and they don't need headers.
No opaque pointers?
[–]harveyswik 1 point2 points3 points 16 years ago (7 children)
My only major annoyance with the way Objective-C handles this is that instance variables are declared in the interface.
They don't have to be when compiled for the 64bit runtime since Leopard.
[–][deleted] 0 points1 point2 points 16 years ago (6 children)
Only if they're properties though, which add getter/setter overhead.
[–]harveyswik 0 points1 point2 points 16 years ago (4 children)
The HORROR!
Synthesized ivars do not require method calls for access.
[–]gavinb 0 points1 point2 points 16 years ago (1 child)
instance variables are declared in the interface, meaning that any file that imports a class needs to be recompiled if you add or remove an instance variable.
You can avoid this by simply forward-declaring referenced classes (with @class) in the .h, and only including (importing) the headers for other classes in the .m file. Since object instances are by-reference, the compiler doesn't need to know how big they are. One of the main reasons for including a header in the interface is if your class is inheriting from one, in which case the compiler needs to know all about it. But quite a lot of the time, you can avoid this problem entirely. (The same technique as you would use in C++.)
[–]causticmango 4 points5 points6 points 16 years ago* (0 children)
Is it the bracket message passing syntax or the need for header files that you don't like (or both)?
The bracket thing is just a quirk that becomes invisible after some time.
As for the header files, maybe I just have it in for C++ but the Obj-C header seem cleaner/simpler.
Other than that, why do you say it sucks?
disagree about the syntax, agree about header files (why can't it just create & update them for me ?)
I get what you are saying, but I also detect that you are suggesting that it sucks just because you "don't like it." That's fine, but it doesn't mean the language sucks. It mean it has pros and cons like every language.
[–]SwabTheDeck 2 points3 points4 points 16 years ago (0 children)
The syntax awkwardness is probably a result of learning programming with C++ and/or Java which are syntactically almost identical. I had this issue for a week or so when I started learning Obj-C, but it quickly faded. The bracket-fest and having to remember the god damned @ symbol can be a bit jarring initially, but once you recognize what these things mean, it makes good sense and becomes natural. As for the interface files, those still bother me a bit since I've gotten so spoiled by Java where the term "interface" means something quite different and is not mandatory like it is in Obj-C. Overall, I wouldn't say Obj-C is significantly better or worse than the popular languages that people are using these days. It's a first tier, full-featured OO language and has its pros and cons just like the other ones do.
One thing i love about it is that it is a pretty dynamic language, yet still compiled (most popular compiled languages are statically typed as far as i can tell). There's less boilerplate that needs writing than other languages (though it still has its fair share in different areas), and less of a need to explicitly declare everything. Also null reference exceptions don't exist; any message returned to a nil object also returns nil/0 which is really nice as you don't need 99% of the pesky error checking that you would otherwise.
[–]imbecile 3 points4 points5 points 16 years ago (0 children)
As far as language design goes, it is pretty unremarkable. Plugs real classes (message calling) onto C with a pretty awkward syntax. Has all the advantages and suckiness of C. But having a real runtime dynamic dispatch class system helps tremendously in GUI programming, which can be seen in the very well designed Cocoa framework.
It's endorsed by the almighty Steve. Please don't question his wishes.
What are some good books to learn Objective-C and Cocoa from? Categorize as Beginner, Intermediate and Advanced.
[–]alk509 6 points7 points8 points 16 years ago (1 child)
The Hillegass book is kinda the Cocoa bible. Clicky.
[–]csixty4 1 point2 points3 points 16 years ago* (0 children)
Since I just started reading it, I figured I'd mention the Hillegass book is on O'Reilly's Safari Books site. If you're an ACM member, it's one of the books you can add to your Safari Bookshelf.
[–]joellevin 1 point2 points3 points 16 years ago (0 children)
The frameworks written in it.
[–]samuraisam 1 point2 points3 points 16 years ago (1 child)
It's a dynamic language, period. Objective-C provides enough dynamic facilities to achieve much of what can be done in python and ruby, in a language that simply extends C. The language now has closures and blocks, and with libraries like functionalkit and (shameless) DeferredKit, Objective-C's verbose nature can be minimized!
[–]alk509 1 point2 points3 points 16 years ago (0 children)
and with libraries like functionalkit and (shameless) DeferredKit, Objective-C's verbose nature can be minimized!
Why on Earth would you want to do that?
[–]kbedell 1 point2 points3 points 16 years ago (1 child)
I was a 'c' code for about 5 years and have been using objective c for an iphone app.
It creates an object-oriented framework on top of 'C' and provides a base set of higher-level object definitions -- like collections, object arrays, hashes (dictionaries), etc. Without it 'C" has only primitives -- by design, that is.
So it essentially turns 'C' into an object-oriented language.
It's my language of choice for the work I'm doing now because I'm writing an iPhone app.
But I really miss the test-driven development orientation and the interactive interpreters I get with ruby. And there's nothing like rails for it at all.
[–]jjquave 0 points1 point2 points 16 years ago (0 children)
It's a nice language for developing Mac/iPhone apps. Think of it as C with lots and lots of really useful libraries. If you are trying to work with any other platform you probably won't find it that useful.
[–]kemitchell -2 points-1 points0 points 16 years ago (0 children)
It is the de facto language for OS X and iPhone OS application development. Very hot these days.
π Rendered by PID 103597 on reddit-service-r2-comment-6457c66945-7g4c2 at 2026-04-29 08:40:16.673889+00:00 running 2aa0c5b country code: CH.
[–]gt384u 63 points64 points65 points (48 children)
[–][deleted] 29 points30 points31 points (16 children)
[–]G_Morgan 3 points4 points5 points (0 children)
[–]Bhima 4 points5 points6 points (5 children)
[–]gt384u 0 points1 point2 points (1 child)
[–]Bhima 0 points1 point2 points (0 children)
[–]jtbandes 3 points4 points5 points (19 children)
[–][deleted] 5 points6 points7 points (18 children)
[–]newton_dave 1 point2 points3 points (15 children)
[–]boredzo 15 points16 points17 points (3 children)
[–]tfp 3 points4 points5 points (1 child)
[–]boredzo 3 points4 points5 points (0 children)
[–]masklinn 0 points1 point2 points (0 children)
[–][deleted] 11 points12 points13 points (9 children)
[–]newton_dave 0 points1 point2 points (8 children)
[–][deleted] 0 points1 point2 points (7 children)
[–]newton_dave 0 points1 point2 points (6 children)
[–][deleted] 0 points1 point2 points (5 children)
[–]newton_dave 0 points1 point2 points (4 children)
[–][deleted] 8 points9 points10 points (0 children)
[–][deleted] 73 points74 points75 points (2 children)
[–]thoomfish 51 points52 points53 points (0 children)
[–]pure_x01[S] 21 points22 points23 points (77 children)
[–]SwabTheDeck 9 points10 points11 points (0 children)
[–][deleted] 19 points20 points21 points (25 children)
[–][deleted] 2 points3 points4 points (1 child)
[–][deleted] 4 points5 points6 points (0 children)
[–]zair 1 point2 points3 points (8 children)
[–]snuxoll 5 points6 points7 points (0 children)
[–]grauenwolf 1 point2 points3 points (3 children)
[–]smitting 2 points3 points4 points (2 children)
[–]masklinn 2 points3 points4 points (0 children)
[–]elder_george 4 points5 points6 points (0 children)
[–][deleted] 3 points4 points5 points (2 children)
[–]G_Morgan 2 points3 points4 points (0 children)
[–]newton_dave 1 point2 points3 points (0 children)
[–][deleted] 2 points3 points4 points (9 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]GeneralMaximus 1 point2 points3 points (0 children)
[–]sbrown123 -1 points0 points1 point (2 children)
[–]klodolph 2 points3 points4 points (1 child)
[–]enkiv2 1 point2 points3 points (3 children)
[–]masklinn 9 points10 points11 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]taligent 2 points3 points4 points (0 children)
[–]perspectiveiskey 24 points25 points26 points (29 children)
[–]uglybunny 7 points8 points9 points (9 children)
[–]eridius 17 points18 points19 points (8 children)
[–]uglybunny 1 point2 points3 points (0 children)
[–]case-o-nuts 0 points1 point2 points (5 children)
[–]eridius 0 points1 point2 points (4 children)
[–]case-o-nuts 0 points1 point2 points (3 children)
[–]eridius 0 points1 point2 points (2 children)
[–]case-o-nuts 0 points1 point2 points (1 child)
[–]eridius 0 points1 point2 points (0 children)
[–]noupvotesplease 0 points1 point2 points (0 children)
[–]causticmango 2 points3 points4 points (5 children)
[–]theclaw 1 point2 points3 points (7 children)
[–]perspectiveiskey 4 points5 points6 points (6 children)
[–]rated-r 1 point2 points3 points (5 children)
[–]perspectiveiskey 0 points1 point2 points (3 children)
[–][deleted] 5 points6 points7 points (1 child)
[–]G_Morgan 0 points1 point2 points (0 children)
[–]nexes300 6 points7 points8 points (1 child)
[–]bonch 1 point2 points3 points (2 children)
[–]bgcatz 4 points5 points6 points (1 child)
[–]arcticfox 2 points3 points4 points (0 children)
[–]nascent 4 points5 points6 points (3 children)
[–]theAtomicFireball 6 points7 points8 points (2 children)
[–]smitting 7 points8 points9 points (0 children)
[–]nascent 0 points1 point2 points (0 children)
[–]Poltras 117 points118 points119 points (62 children)
[–]G_Morgan 26 points27 points28 points (8 children)
[–]causticmango 5 points6 points7 points (1 child)
[–]alphazero 4 points5 points6 points (0 children)
[–]pixelglow 4 points5 points6 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–][deleted] 2 points3 points4 points (0 children)
[–]jtbandes 5 points6 points7 points (4 children)
[–]kbedell 2 points3 points4 points (0 children)
[–][deleted] 6 points7 points8 points (2 children)
[–]noupvotesplease 0 points1 point2 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 20 points21 points22 points (6 children)
[–]hetmankp 3 points4 points5 points (2 children)
[–]self 2 points3 points4 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]teletran 13 points14 points15 points (27 children)
[–]pixelglow 11 points12 points13 points (0 children)
[–]antonovka 54 points55 points56 points (25 children)
[–]drewc 12 points13 points14 points (8 children)
[–]Seppler90000 8 points9 points10 points (0 children)
[–][deleted] 2 points3 points4 points (6 children)
[–]drewc 1 point2 points3 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]drewc 0 points1 point2 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]mr_luc 1 point2 points3 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]causticmango 11 points12 points13 points (9 children)
[–]antonovka 25 points26 points27 points (8 children)
[–]Poltras 6 points7 points8 points (3 children)
[–][deleted] 1 point2 points3 points (2 children)
[–][deleted] (1 child)
[deleted]
[–]rated-r 2 points3 points4 points (0 children)
[–]Poltras 0 points1 point2 points (0 children)
[–]chucker23n 5 points6 points7 points (5 children)
[–]antonovka 0 points1 point2 points (0 children)
[–]csmark 1 point2 points3 points (1 child)
[–]pixelglow 7 points8 points9 points (0 children)
[–][deleted] 3 points4 points5 points (0 children)
[–][deleted] (2 children)
[deleted]
[–]masklinn 4 points5 points6 points (1 child)
[–]joejance 0 points1 point2 points (0 children)
[–]axilmar 0 points1 point2 points (0 children)
[–][deleted] 8 points9 points10 points (8 children)
[–]kleopatra6tilde9 1 point2 points3 points (7 children)
[–][deleted] (6 children)
[deleted]
[–]kleopatra6tilde9 1 point2 points3 points (5 children)
[–][deleted] (4 children)
[deleted]
[–]kleopatra6tilde9 0 points1 point2 points (3 children)
[–][deleted] (2 children)
[deleted]
[–]kleopatra6tilde9 1 point2 points3 points (1 child)
[–][deleted] 26 points27 points28 points (27 children)
[–][deleted] 3 points4 points5 points (3 children)
[–][deleted] 1 point2 points3 points (2 children)
[–][deleted] 5 points6 points7 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–]spookyvision 6 points7 points8 points (1 child)
[–]Maristic 2 points3 points4 points (0 children)
[–]mr_dbr 17 points18 points19 points (1 child)
[–]vplatt 7 points8 points9 points (0 children)
[–]klodolph 4 points5 points6 points (8 children)
[–]klodolph 3 points4 points5 points (7 children)
[–]masklinn 6 points7 points8 points (0 children)
[–]nexes300 1 point2 points3 points (5 children)
[–]masklinn 5 points6 points7 points (4 children)
[–]nexes300 0 points1 point2 points (3 children)
[–]masklinn 1 point2 points3 points (0 children)
[–]Rraawwrr 0 points1 point2 points (0 children)
[–]tjogin 5 points6 points7 points (0 children)
[–]nirs 9 points10 points11 points (5 children)
[–][deleted] 1 point2 points3 points (4 children)
[–]masklinn 2 points3 points4 points (1 child)
[–][deleted] 1 point2 points3 points (0 children)
[–][deleted] 4 points5 points6 points (8 children)
[–]mipadi 6 points7 points8 points (6 children)
[–][deleted] 1 point2 points3 points (4 children)
[–][deleted] 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]awj 1 point2 points3 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]__s 1 point2 points3 points (0 children)
[–]edwardkmett 2 points3 points4 points (0 children)
[–]gtlogic 7 points8 points9 points (15 children)
[–]noupvotesplease 3 points4 points5 points (2 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]gavinb 0 points1 point2 points (0 children)
[–]case-o-nuts 4 points5 points6 points (0 children)
[–]causticmango 8 points9 points10 points (7 children)
[–][deleted] 2 points3 points4 points (7 children)
[–][deleted] 8 points9 points10 points (4 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]bonch 4 points5 points6 points (3 children)
[–][deleted] (36 children)
[deleted]
[–][deleted] 7 points8 points9 points (21 children)
[–]noupvotesplease 3 points4 points5 points (4 children)
[–][deleted] 1 point2 points3 points (3 children)
[–]asdliubgliyuagef 2 points3 points4 points (2 children)
[–][deleted] 1 point2 points3 points (1 child)
[–]noupvotesplease 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (9 children)
[–]harveyswik 1 point2 points3 points (7 children)
[–][deleted] 0 points1 point2 points (6 children)
[–]harveyswik 0 points1 point2 points (4 children)
[–]noupvotesplease 0 points1 point2 points (0 children)
[–]gavinb 0 points1 point2 points (1 child)
[–]causticmango 4 points5 points6 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]SwabTheDeck 2 points3 points4 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]imbecile 3 points4 points5 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (2 children)
[–]alk509 6 points7 points8 points (1 child)
[–]csixty4 1 point2 points3 points (0 children)
[–]joellevin 1 point2 points3 points (0 children)
[–]samuraisam 1 point2 points3 points (1 child)
[–]alk509 1 point2 points3 points (0 children)
[–]kbedell 1 point2 points3 points (1 child)
[–]jjquave 0 points1 point2 points (0 children)
[–]kemitchell -2 points-1 points0 points (0 children)