Not a problem - naming them all the same would probably be a bad idea anyway. Typically you'd name your most common one the simplest, e.g.
drawAt(x,y,z)
and then name the others more explicitly:
drawAtRPZ(...) drawAtRTP(...)
Or if they are all used commonly, then you'd name the first one more explicitly, e.g. drawAtXYZ(...). IMO just as readable as the ObjC but less redundant in typical usage:
Gah, another example of not seeing the forest for the trees. I keep making the mistake of assuming that people will be able to grasp the principle and not fixate on the specific example (I just grabbed a random sample off StackOverflow that illustrated the point). The point is the readability of the code:
[nc addObserverForName:AVCaptureDeviceWasDisconnectedNotification object:nil
queue:tasks usingBlock:^(id) {
dispatch_async(dispatch_get_main_queue(), ^()
{ [self refreshDeviceLists]; });
}]; (somewhat humorously, I had to combine some of the lines because when I pasted it in using Xcode's default formatting,/. refused to post it because I had too much whitespace)
I get it, some people find that sprawl pretty or readable or whatever. Others (like me) find it unnecessarily verbose and that it ruins readability. The fact that I grabbed a poor example off SO is dumb luck, but look over any sizable ObjC app and you'll see many similar examples (not of redundant message sending but of awkward and overly verbose message sending).
Calling a function with a bunch of hardcoded magic numbers is far, far less common than calling a function with variables. And when examples like yours occur, there darn well better be a comment nearby explaining the magic numbers. So in a well written program, the first example would be either
// draw the 2nd item at (1,1,1) to get things started [self drawAtX:1 Y:1 Z:1 index:1]
or
// draw the 2nd item at (1,1,1) to get things started self.drawAt(1,1,1,1)
So again, having named parameters with every single invocation isn't adding a lot of value. And even if you were to decide that the ObjC way is more readable in this specific corner case, that's a tiny bit of benefit to justify the cost of requiring it all the other times.:)
While lists and tuples are both sequence types, semantically they are not Python's version of mutable and immutable list types
I don't see why they aren't. Traditionally, the difference between a list and a tuple - other than immutability - is that tuples have separate type for every element, while lists must all have a single uniform element type (or at least supertype). But that only applies in statically typed languages. In Python, literally, the only difference between the two is mutability - other than that, they represent the same exact concept, that of a ordered indexed sequence of elements.
To a limited extent maybe, but there is a typically a pretty big difference in cases where they are used. Tuples aren't so much for cases where you have a different type for every element, they are more of a position-based record. In a list, the fact that an item is in position 4 vs position 7 is just a function of the ordering of the list, whereas in a tuple the difference in a position/typically/ implies something about what that value is. For example, if you're passing around x,y,z coordinates, you could define a class for that or you could just pass around a (x,y,z) tuple, and by your program's own convention position 0 is the x coordinate, etc. You/could/ use a list in this case, but it's rare - not because the language would prefer you do it one way or another, but because the intent of what you're doing is different.
This also fits in well with the hashability of tuples vs lists - the latter aren't hashable, so they can't be used as e.g. dictionary keys, but typically that also simply makes a lot of sense: a tuple usually represents a record or a distinct "item", so it makes sense that it should be usable as a dictionary key because it's more or less a specific "thing", whereas a list can't be used as a dictionary key and this also typically makes sense: a list of a bunch of things as opposed to being something specific, so it's less sensical for it to be used as a key anyway.
nor does their use map to where you'd use an NSArray vs an NSMutableArray in ObjC
(FTFY)
Why wouldn't it? Again, so far as I can see, NSMutableArray is almost exactly identical to Python list in terms of semantics - maintains insertion order, O(1) access by index, amortized O(1) append. Ditto for NSArray/tuple. Admittedly I'm not an Obj-C expert, so I may not be familiar with some important pattern here that I am missing.
I'm not saying that you/couldn't/ use them in the same ways they are used in ObjC, just that that is not typically how they are used. NSMutableArray is almost exactly to a Python list in terms of semantics, but an NSArray does not map to a tuple in terms of how they get used most often in a Python program and vice versa.: in ObjC it's less common (as far as any ObjC code I've ever seen) for an NSArray to represent a simple record (with meaning of items implied by their position in the array), and it's relatively uncommon in Python programs to use tuples as a way to achieve immutability to "protect" an object or something. It might happen (sys.argv is the one case that comes to mind, but it's debatable that using a tuple was the right move there), but it's far less common than using a tuple as a lightweight record. For example, a function's args list (def foo(*args, **kwargs)) is a tuple less because of the desire to achieve immutability and more simply because the position of items matters.
The distinction between NSMutableArray and NSArray simply doesn't exist in Python (or Javascript or any number of other languages), and my assertion is that those languages aren't lacking in any way because of it (specifically, I mean that I have never, ever seen a case where not having that distinction has caused any problems). And because they are apparently not lacking (meaning: while problems could occur in theory, they don't ever seem to occur in practice), it begs the question as to whether or not making that distinction in ObjC/Cocoa/GNUstep actually adds any real world value (and my assertion is that it doesn't - it's all cost and no real world benefit).
Ok, so inherent in your reply is the assumption that I haven't spent time in things like functional programming or that I'm not aware of that stuff. Have you considered the possibility that I/have/ actually spent a lot of time both studying and using functional programming but have drawn a different conclusion than you?
The accidental mutation of objects is almost always a/theoretical/ set of problems - it just does not occur in practice unless you have some other problem (like not testing your code). Making containers mutable by default is not the same as giving license to any bit of code to mutate them - far from it. In, e.g. ObjC, whether or not a method mutates an object is denoted first and foremost by the contract the API provides - the description of the method, the documentation, the shared understanding of what the method does. The language-level enforcement is a distant second. In a language where the containers are mutable by default, that primary - and most important - contract remains in place. Because the secondary enforcement is such a distant second anyway, the lack of it doesn't suddenly introduce a whole new set of problems or anything. And that's the crux of my point: introducing an immutable container and then forcing that distinction to be made everywhere doesn't actually add any real-world value.
So, if I may, let me throw this back at you: what I find most ill-informed is your assumption that not providing immutable containers creates any real-world problems. You should really spend some time studying how other languages do this and manage to get by just fine.:)
Let's move this out of the theoretical space - can you help me see at least a/plausible/ example of a bit of code that would accidentally/unexpectedly mutate e.g. an array that wasn't intended to be mutated? Having never encountered this in practice despite using such languages for decades, I'm honestly having trouble coming up with something that isn't totally contrived. I mean, what we're talking about is essentially a function that (a) doesn't do what it is documented to do, and (b) most likely only mutates the object in rare cases (otherwise the very first time you used it you'd see that it is broken), right?
Method signatures are often ridiculously long (see NSBitmapRep's initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel: method)
Parameter names in method calls are/always/ named. You can't just say obj.someMethod(x,y). It's always [obj someMethodForX:x y:y].
The above combine to make even the most basic operations tedious. Want to trim leading/trailing whitespace off a string? Enjoy [someString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
I consider this an advantage. All those folks who talk about self-documenting method names finally have a place to hang their hats.
Yep, I recognize that some people like this and consider it an advantage. I don't - to me it just gets in the way of getting the job done and does nothing to increase readability since the variable names themselves will already convey nearly as much (or as much) meaning.
Immutable arrays, dictionaries, sets, strings. I get it, it can be useful for performance to know something is immutable (maybe, I'm not that convinced). But the common use case is most certainly mutable, so/that/ should be the default, e.g. NSArray should be mutable and then if needed there can exist some NSImmutableArray or something. But no, they did it the other way around.
Immutability is about more than just performance. Java and C# both have immutable strings. Good programming practice often recommends immutability as a way of enforcing contracts and avoiding unintended side effects. Some languages avoid mutability for any object.
Yeah, see the other posts on this sub-thread. Again, I understand that some consider the non-performance aspects an advantage, but I don't - I've never come across an instance where I thought to myself, "whew, thank goodness that object was immutable!".
I'm a strong proponent of duck typing and kin so I find language-level enforcement of mutability a nuisance. I understand the theoretical benefits of that type of enforcement, but again in practice find it more cost than benefit, and IMO depending on it is poor programming practice, i.e. if I'm being a good developer and writing good code and testing my code, then that sort of language-level enforcement does me no good whatsoever. If I'm being sloppy and/or not testing my code, then that sort of language-level enforcement isn't really going to be enough to save me.
it drives home the point of how absurd they can be.
No, it doesn't. In fact, it makes a very good case for Obj-C's syntax in situations where you have a large number of parameters.
I guess it's a matter of opinion. Variable names tend to be pretty descriptive, so having named parameters adds little value IMO, e.g. this sort of thing seems goofy to me:
[self drawAtX:x y:y z:z index:index]
whereas
self.drawAt(x,y,z,index)
is more readable (to me at least). Similarly, a method definition of
Since this isn't required by the language (though apparently encouraged by one of the largest backers of the language), I can't really fault ObjC/the language/ for this, but Cocoa is definitely guilty, and the redundancy in the variable names and parameter names/is/ IMO a flaw in the language - it just tends to make the source code noisy. Since code is read more than it is written, to me this is a real problem.
See my reply elsewhere - several of my customers have analytics to back up their claims that a decent size of their user base is on 3.1.3 (iphone) or 3.2 (ipad).
While lists and tuples are both sequence types, semantically they are not Python's version of mutable and immutable list types, nor does their use map to where you'd use an NSArray vs an NSMutableArray in ObjC.
.. if we can use the latest and greatest features, which is often not the case
Sometimes. The hugest jump in improvement, by far, was ARC - and that support goes back to iOS 4 even though they introduced it with iOS 5. You can easily use that today, and have been able to really for a while now as there are very few iOS 3 devices around anymore.
Some of my customers and their analytics would disagree with you.:) (I can't drop
I think a lot of it comes from the inability to have any sort of mixin class.
What about categories!!!! Especially with the newer ability to also create variables local to them (which there have been means to do for awhile in different ways).
Thanks for the very thoughtful response.
You nailed it - the inability to add new variables w/o hackery was a big limiting factor such that we tend to use categories just for adding utility functions, e.g. to CGRect or something. I think categories with instance vars will help a lot once we can use them.
The single inheritance model and a strict class hierarchy discourages writing reusable code. For example, if I have an app that runs on iPad and iPhone and they share a common screen (from the user's perspective although the layout/design might be significantly different), it's a real task to write a common parent class holds the common code.
I find that protocols work better that multiple inheritance any day.
I don't. They have their place, sure, and the whole delegate model I think is a better fit than subclassing in/some/ cases, but in large part they seem aimed at solving two different sets of problems - protocols are often a good fit when you want to say that an object conforms to, well, a protocol, whereas a mixin class can be really useful when you just want to augment a class's functionality, perhaps for entirely internal purposes.
Similarly, there's no way to have a truly dynamic object with a clean syntax, e.g. in Python/ruby/js/and a host of others you could have a quick little object you use to pass state around, kind of like a struct that has its members added on the fly, e.g.: x = new Object() ; x.name = 'dave' ; x.age = 3. There is literally no way to do that in ObjC - the best you can do is create mutable dictionary and use its verbose syntax.
Well, it isn't impossible, but it does require some deeper knowledge. Objective-C has a concept called KVC, where you can refer to properties by strings, very useful stuff. There's also a mutable dictionary called the associationObject for each object. You could write the KVC reader to put the values into an assoiciated object, which incidentally is pretty much exactly what Python does internally.
Now, I'd question whether you really want to do this, but it's certainly possible. One thing I like about Obj-C is that things like categories, KVC, KVO, forwardInvocation, exchangeSelector, et al. are there if you really want to use them.
Use with caution, of course.
Sadly, I've tried all of that (it was actually for our Python-ObjC bridge in fact!). Care to show an example that doesn't result in tons of compiler warnings? I'll buy you a virtual milkshake if there's a way (and disabling warnings doesn't count, hehe).
I think you've missed the point I was trying to make.
No, I'm pretty sure I didn't. I just disagree with it.:)
When the array is local to your code, yes, it doesn't really matter if you start with it being mutable or immutable (unless you also do multithreading, but that's another story). The problem is at the API boundary of your code. If you declare a function accepting an NSMutableArray, it will only be able to accept that, and not an NSArray. If the caller only has an NSArray (because he obtained it from another API that returned that - which it did because it doesn't want anyone mutating that data), he now needs to do an explicit copy to make it mutable. Which is all a waste if your function doesn't actually need a mutable array, and only uses non-mutating operations on it. It's strictly better to make people declare the widest type possible at the API boundary, since it makes their code more generic.
It's definitely not 'strictly better'. Again, we might be talking past each other, but my point is that you're burdening people with a detail that they don't care about most of the time. In a programming language, that's a really, really big deal.
The argument for immutability seems to be couched in the desire to prevent accidents or something. If a function modifies an object you passed to it and you weren't expecting that to happen, what exactly are you doing? (i.e. did you misunderstand what the function does? Is the function buggy?) In all cases it seems like there are other issues going on, and having the language try to save you isn't really the right solution anyway.
I completely understand the notion that *if* your language or standard library distinguishes between mutable and immutable types, then using one over the other makes your API as generic as possible. I get it. I'm just saying that I don't think that distinction is very helpful most of the time, and yet by making that distinction you force people to worry about it even when they don't care.
Python has a very different story in that regard because of duck typing - you don't declare functions as taking lists, either mutable or immutable. You just work with an argument as if it were a list, and then it either implements the API surface that you need, or it does not.
That's exactly my point. Since we're talking somewhat about language design, I used that as an example of how this question of array mutability is not one inherent to programming languages, nor is the ObjC way clearly superior. Rather, it is a design decision that is a part of ObjC, one that I think has cost but little if any real-world benefit, and therefore a flaw in the language (again, it's subjective, but for my part it's a real flaw). The Python example was just to point out that other languages didn't see the need to burden the developer with it, and they get on quite nicely - i.e. to me it's a real world example of what would happen if you didn't introduce that distinction and it turns out that things work just fine without, which is why coming to ObjC from other languages it often feels like you have to do things because the language/library requires it, not because they are actually useful to you or the problem at hand.
I'm sure it's just a coincidence that the example you randomly plucked out of the air is in fact the longest method name in the entire Cocoa API
Haha, of course not - but it drives home the point of how absurd they can be. And while it's an extreme example it's also not/that/ extreme - there are quite a few that are very long, and a host that IMO qualify as "goofy long". I think explicitness/can/ be beneficial, but wanton verbosity is a net negative. As mentioned elsewhere, I recognize that this is subjective to a degree, but for me it is a real drawback to the language. I've used ObjC alongside other languages for years and strongly dislike the ObjC way, that's all.
You're a bit out of date here, and your code is probably incorrect (unless you did in fact intend to create a new root class). That should be:
LOL, yes, I've been severely punished for writing a snippet of code off the cuff like that, and I apologize. I am repentant and will try to avoid it, especially since it invites people to fixate on the minutiae while overlooking the larger point I was (apparently ineffectively) trying to make.
Xcode often pegs multiple CPUs when it's just sitting there
I've seen XCode use a lot of CPU while it's indexing a project I've just checked out. If you think it's not doing anything, check the status display and you'll probably see that it's not as idle as you've assumed.
I'm sure it's doing/something/, it's just not giving any hints as to what that is. The status display shows no activity, and the sudden jump is not typically tied to any user action that we can tell. We'll just be working in another app and notice the system becoming sluggish. We'll bring up the activity monitor and lo and behold Xcode is going nuts.
Haven't touched build settings, not doing anything 'silly', but I suppose that depends on your definition of silly. Here's just one example: in iOS on app startup, you shouldn't do very much in the initial method call into your app delegate as it is time sensitive, so if you want to do something around the time of init but perhaps before all the UI loads, then you might do e.g.:
No warning. The same was more common when UIKit could only be touched from the main thread. This is just one example, so to anyone who is itching to reply and say "you should use a different approach during app launch", let me pre-emptively suggest you're missing the point.;-)
Well, a *reason* at least. Whether or not it's a good one is very debatable.:)
Immutable collection operations are a strict subset of mutable ones, which means that e.g. NSMutableArray is a subclass of NSArray. So, if someone declares a method that takes NSArray, you can pass an NSMutableArray to it - the method is generic in that sense.
Hmm.. the essence of this argument though is that it works this way because it was designed this way which, while true, doesn't affirm that the design was a good one. (More below)
On the other hand, if NSArray was mutable, and deriving from something like NSImmutableArray, then most people would likely forget about the latter, and use NSArray everywhere - including method signatures - even when they really only use the read-only part of the interface. The way it is now, it forces the person writing the API into a good habit: he'll write NSArray first because it's shorter, and will only change it to NSMutableArray when/if he actually needs some operation that's only available there. Thus, his functions will not be less generic than needed.
I think the key part of your statement is "most people would likely forget". And I think you're absolutely right, and I think that would actually be a *good* thing. A common problem with what I consider to be sucky programming languages is that they make the developer worry about things they just don't care about (see the other part of this thread, where we talk about prefixing string literals with '@'). 999 times out of a 1000, the developer doesn't care if a particular array is mutable or not, but the language makes them think about it - often earlier than they are ready to properly think about it as well. By itself, it's a tiny thing, but it's just this sort of thing that pervades ObjC/Cocoa (other languages are at fault too, but we're talking about ObjC).
The contract implicit in an API will always make it clear whether the object will be modified or not, so you really don't need the language to police it for you. For every one time it ends up helping you (because you were sleepy and ignored the docs or the function name or whatever), there's about a million times where it does/not/ help you. So you incur the cost every time but receive the benefit a statistically insignificant portion of the time.
Let me given you a counter example: in Python arrays are mutable. At several companies we've deployed all kinds of apps in Python - mobile, games, web backends, desktop apps, systems programming type apps, servers, etc. etc. - basically everything. (Note I'm not trying to argue the virtues of Python over your language of choice, just establishing that here's a language that has mutable arrays and we've used that language in a huge variety of apps and scenarios). Do you know how many times we've been bitten by the fact that we couldn't prevent a called function from modifying an array? Zero. Literally, as far back as I can remember (we started using Python in the late 90s) I can't think of a single case where this was a problem. Not a one. And yet in that time we used arrays thousands of times. What would have been the benefit of the language forcing us each time to specify the mutability of those arrays?
Method signatures are often ridiculously long (see NSBitmapRep's initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel: method)
That's rather the point. It make code easier to read and understand when you can see, in the method invocation itself, what all of the parameters are for.
Parameter names in method calls are/always/ named. You can't just say obj.someMethod(x,y). It's always [obj someMethodForX:x y:y].
Again, rather the point. Otherwise your above example would endue as initWithBitmapData(p,w,h,b,s,a,p,c,f,r,b).
I'll concede that this one is subjective, while stressing that for me it's one of the reasons the language sucks.:) I do understand the intent behind them, I feel quite strongly however that it makes for a cumbersome language to use.
The above combine to make even the most basic operations tedious. Want to trim leading/trailing whitespace off a string? Enjoy [someString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
Autocomplete makes this rather irrelevant, no? Especially the much improved autocomplete in Xcode4+.
Autocomplete helps, no doubt. And the newer autocomplete helps a lot. Coming from other languages though the net result feels like the language made something unnecessarily cumbersome and several revisions of the primary IDE of that language have done wonders at making up for it to a degree, without ever quite getting there completely.
Immutable arrays, dictionaries, sets, strings. I get it, it can be useful for performance to know something is immutable (maybe, I'm not that convinced). But the common use case is most certainly mutable, so/that/ should be the default, e.g. NSArray should be mutable and then if needed there can exist some NSImmutableArray or something. But no, they did it the other way around.
That you don't actually understand this point is pretty telling. Performance isn't the only reason to make arrays and such immutable by default. It also makes such structures safer to pass around, especially to outside code, without having to worry about the data getting modified unexpectedly.
Ah, the old "the language is protecting me" argument. It can have its place, but highly dynamic languages like Python or Ruby or C# or any number of others invalidate your point. That *you* don't understand this point is pretty telling.:)
Memory management (up until recently) was neither fully manual nor fully automatic and ownership was based on naming conventions
Ownership is always based on naming conventions, or else there would be no predictability and the language would be unusable.
Except for the fact that many other languages get by just fine without it. If ObjC would be "unusable" without it (which I don't believe would be the case), then that's just another flaw of ObjC and not programming languages in general.
Being a superset of C, they couldn't provide an object-oriented array class using the normal array syntax, so instead you have tedium like [myArray objectAtIndex:2]
"Fixed" in enhancements coming with Xcode 4.4.
I had a similar reaction when Java "fixed" this with syntactic sugar or whatever the solution was. These types of changes are unsettling to me because I'm at least somewhat aware of the tricks needed to pull it off. When any complex system like a programming language and compiler and runtime, you get cruft built up over time, so a language having to bolt on something so fundamental makes me doubt the longevity of the language - undoubtedly there will be unintended side effects or unfo
Technically these days you just need one thing, the @property. You don't need anything else. Hard to get less redundant than one definition.
On iOS, you never need the ivar that you put in, so that's needlessly redundant. That's user error, not a language issue. That reduces you to three required references at worst. The property, the synthesize, and the dealloc reference. New LLVM makes the synthesize go away, older LLVM with ARC killed the dealloc reference. So these days you're down to 1 line of code.
*If* you have the luxury of being able to use all of the latest and greatest features, that can be the case, yes. That's very often not the case though. But yes, you make a valid point.
Like I said, you don't seem to have a firm understanding, which is kind of dangerous when critique a language that you don't really know. I took two years of Spanish in high school, doesn't put me in a position to claim I understand Spanish and it's a horrible language.
Well, let's run with that example: "two years" of Spanish typically means "5 hours of sitting in a class and some homework each week, for 9 months, then a 3 month break, repeated", which is incredibly different from, say, living in Argentina by yourself for the same amount of calendar time. With the former you end up with at best a superficial handle on the basics of the language, while in the latter you can achieve a really good degree of fluency.
If you are developing code in a language day in and day out for a couple of years, that's close to the latter, and it's plenty of time to understand quite a bit about the language. More to the point of this whole thread, however, in far less time you can come to have a very good feel for how that language compares to others. While you and others have made some very legitimate points about a few individual places where I'm still using old-fashioned ObjC or where in my haste I failed to run a jotted down snippet of code through a mental compiler, my takeaway from all of this is that ObjC is incrementally less lousy than I thought. So far nothing there's little to suggest that fixes to ObjC have significantly closed the gap relative to more modern alternatives.
I understand all of what you're saying, merely pointing out that the compiler still issues some warnings that, according to your reasoning, it should not. In some cases it already generates a warning when you use a selector it doesn't recognize (e.g. [ someMessage], or [self someMethodDefinedAfterThisOneAndNotDeclaredInTheInterface]).
You have a property, why are you making a class var?
I'll readily concede that it's habit mostly - because IIRC pre-64-bit Mac we had to.:) Obviously I'm catching a lot of grief because I wrote a couple of quick lines into a post without really proofing it, writing it more as a "you know what I mean" than a "this is precisely the way to do it". I appreciate everyone's right to do this (and it's a long part of the/. tradition) but to me it's a case of not seeing the forest for the trees. As mentioned elsewhere, the cumbersome nature of ObjC is most noticeable to me when I have to hop back and forth between it and pretty much any other language we use on any project. So, yes, while there are some flaws in what I typed into ye olde form element, I think it's overshadowing the point of just how much/work/ it is to write code in ObjC compared to many other languages.
Now, I don't have a whole lot of data, so consider this purely anecdotal, but this is what I have found to be universally true: people who use ObjC and also program a lot in other languages tend to dislike ObjC, while people who really like ObjC don't tend to be as broad in their use of languages. Both sides can draw their own conclusion from that.:) For me, if I'm working on something else and then hop in to ObjC for a bit, it feels exactly like going back to assembly did back in the day when we finally transitioned to C for most everything: once we had gotten used to the higher level nature of C, dipping into assembly felt archaic. Those who still swore by assembly hadn't really spent much time in other pastures, and would extol the virtues of modern macro assemblers and other new features.
Those are just the kinds of things that make people who have been working with ObjC a long time think of developers new to the language, or at least not spending any time keeping up...
That's a fair point, although I would make a minor counterpoint that there is often a long time between when a new feature becomes available and when it becomes usable in practice due to the need to support legacy projects and code, so I think it's somewhat expected to discount some of the new features to a language (granted, I know these specific ones were added in what Apple calls the 'modern runtime' or some such, but still there are features like ARC and on some projects blocks that are still unusable to me due to legacy needs).
not to mention the complaint about delayed selectors, they are often abused by people who don't really understand why something doesn't work and just pushes the code out to a delayed call
Well, I couldn't really say whether or not other developers use them, nor does their abuse imply that they are bad - they are a standard feature and legitimate to use my frustration with them still holds.:)
Your whole post was valid perhaps two years ago, but there are not many items you are complaining about that are real issues anymore
... if we can use the latest and greatest features, which is often not the case. It's great that these warts are being fixed, but given the choice I'd much rather just choose a more modern language that didn't have them in the first place. Perhaps that's part of the root of it all for me - the unique features of ObjC provide very little in terms of benefits over other choices available today. If it weren't the "standard" language for Mac/iOS development I'd never touch it again.
I do exactly the thing you mentioned (a common base class that is reused between iPhone/iPad instances of those classes) and have not found that to be a problem. What do you feel is limiting in that regard?
I think a lot of it comes from the inability to have any sort of mixin class. It's common for us to need e.g. a bunch of similar functionality on multiple iPhone screens, suc
It's more than just text completion: you have to remember enough to even get started. I've been programming in ObjC for years and sometimes still have a Monday morning brain fart trying to remember stuff, especially if I'm working on a project that involves hopping between multiple programming languages. Want to split a string into its comma-separated parts? Is it 'parts'? 'items'? Ah, no, it's [NSArray componentsSeparatedByString:].
As implied above, if you're writing in ObjC then most likely you're writing for Mac/iOS (I'm ignoring the sliver of people using GNUstep). Every 8 or 9 months I try ditching Xcode (I use Vim for all other development) and even once you get the autocompletion set up for Cocoa (not an easy task), it never works quite right.
One other thing to keep in mind is that the interaction for autocompletion in ObjC isn't the same as what you'd find in e.g. C, there are a few additional wrinkles. For example, if a parameter is actually a message send to another object (e.g. [foo call:[otherObj bar]]) and you don't put that 2nd bracket in there, the code completer often gets confused and puts it in the wrong place. Moving between parameters is a bigger visual jump since every parameter is named. There are a few things like this that make autocompletion a much more complex experience for the developer than what you'd find in other languages. Is it a huge burden? No, but it's just one more layer of annoying.
Well, I think the point still stands, especially considering that the code for that example is split across two files (the.h and the.m) - i.e. the language is needlessly verbose even with a few minor improvements (i.e. not using self.title= doesn't reduce the number of lines of code, for example, and not needing a backing ivar chops off a couple of lines, but it glosses over the large point of why on earth any of that should be needed in the first place. It's 2012 for crying out loud.).
That's great that it can be less redundant now, but going from 4 mentions of a variable to 2 or 3 just before you can do anything with it means the developer is still doing stuff for the language, and not the other way around - i.e. the language design flaw remains, even if partially covered by a band-aid. And I think that kind of gets to the larger issue: given that there are so many available languages today, I'd rather choose something that is fundamentally cleaner over one that has a bunch of junk bolted on in an attempt to keep the language relevant.
That's irrelevant - the compiler could at least issue a warning when you're using the selector literal syntax. It's no different than the compiler issuing a warning when you send a message to an object using a selector that may not exist even though that too could be valid at runtime.
- Maybe it's a generational thing for languages, but once you take OOP features onto C in an attempt to modernize it, then you naturally are going to think about using it in places where you would use some higher level, more modern language, or at least compare it to the features of higher level, more modern languages. In this respect ObjC falls down, and IMO, rather badly. Then again, C++ does too, so I guess it's in good company. There are so many other choices out there that don't get in the way as much. This may sound goofy, but C is just C - it's not pretentious and pretending to be a Java or a C# or whatever. It's just C and so going into it you just approach development a little differently, and that approach has worked pretty well and remained steady for the past 25 years (probably longer, but I don't have any experience with it farther back).
- Most development - in any language - involves more than just the language. It's also using a standard library and any number of add on libraries. I'm fairly confident that a relatively small number of people use ObjC outside of Cocoa on iOS and Mac OS X, and even fewer outside of the group of people that use either Cocoa or GNUstep or whatever it's called. Because those libraries are written to use e.g. the ObjC message sending syntax and object life cycle semantics, in practice if you use ObjC then you are very likely going to be using the ObjC language features (i.e. the fact that you/could/ write your app all in straight C is irrelevant since (a) you couldn't call the Cocoa libraries and (b) if you did that, you wouldn't be using ObjC probably anyway). So, yes, the extra features/do/ in fact degrade what was there in the first place. A classic example would be an array. If you took all of the ObjC programs out there and looked at all the cases where arrays were used, I'm willing to bet that the overwhelming majority of the cases don't use a C array but instead use an NSArray. The latter is somewhat more powerful but unfortunately incredibly cumbersome to use relative to a good ol' C array. In theory the old C array is there, but in practice it largely isn't.
Honestly, from your example code, it certainly looks like you've worked with Obj-C, but it doesn't look like you really had a strong understanding of it. Not that I don't blame you, with Obj-C 2.0 it became a little harder to understand, but Apple is cleaning that up.
LOL, you deduced that from a couple of lines of code hurriedly typed into a web form? Gimme a break. I could just as easily say something like, "based on your reply, it looks like you've worked with Obj-C, but not much else; you haven't been exposed to enough development to see the weaknesses in your language of choice or appreciate the value of the alternatives." (I'm not saying this is the case, but see how it comes across?)
Not a problem - naming them all the same would probably be a bad idea anyway. Typically you'd name your most common one the simplest, e.g.
drawAt(x,y,z)
and then name the others more explicitly:
drawAtRPZ(...)
drawAtRTP(...)
Or if they are all used commonly, then you'd name the first one more explicitly, e.g. drawAtXYZ(...). IMO just as readable as the ObjC but less redundant in typical usage:
self.drawAtRPZ(rho, phi, z)
is less noisy to me than
[self drawAtRho:rho Phi:phi Z:z]
Gah, another example of not seeing the forest for the trees. I keep making the mistake of assuming that people will be able to grasp the principle and not fixate on the specific example (I just grabbed a random sample off StackOverflow that illustrated the point). The point is the readability of the code:
[nc addObserverForName:AVCaptureDeviceWasDisconnectedNotification object:nil /. refused to post it because I had too much whitespace)
queue:tasks usingBlock:^(id) {
dispatch_async(dispatch_get_main_queue(), ^()
{ [self refreshDeviceLists]; });
}];
(somewhat humorously, I had to combine some of the lines because when I pasted it in using Xcode's default formatting,
I get it, some people find that sprawl pretty or readable or whatever. Others (like me) find it unnecessarily verbose and that it ruins readability. The fact that I grabbed a poor example off SO is dumb luck, but look over any sizable ObjC app and you'll see many similar examples (not of redundant message sending but of awkward and overly verbose message sending).
Calling a function with a bunch of hardcoded magic numbers is far, far less common than calling a function with variables. And when examples like yours occur, there darn well better be a comment nearby explaining the magic numbers. So in a well written program, the first example would be either
[self drawAtX:1 Y:1 Z:1 index:1]
or
self.drawAt(1,1,1,1)
So again, having named parameters with every single invocation isn't adding a lot of value. And even if you were to decide that the ObjC way is more readable in this specific corner case, that's a tiny bit of benefit to justify the cost of requiring it all the other times. :)
While lists and tuples are both sequence types, semantically they are not Python's version of mutable and immutable list types
I don't see why they aren't. Traditionally, the difference between a list and a tuple - other than immutability - is that tuples have separate type for every element, while lists must all have a single uniform element type (or at least supertype). But that only applies in statically typed languages. In Python, literally, the only difference between the two is mutability - other than that, they represent the same exact concept, that of a ordered indexed sequence of elements.
To a limited extent maybe, but there is a typically a pretty big difference in cases where they are used. Tuples aren't so much for cases where you have a different type for every element, they are more of a position-based record. In a list, the fact that an item is in position 4 vs position 7 is just a function of the ordering of the list, whereas in a tuple the difference in a position /typically/ implies something about what that value is. For example, if you're passing around x,y,z coordinates, you could define a class for that or you could just pass around a (x,y,z) tuple, and by your program's own convention position 0 is the x coordinate, etc. You /could/ use a list in this case, but it's rare - not because the language would prefer you do it one way or another, but because the intent of what you're doing is different.
This also fits in well with the hashability of tuples vs lists - the latter aren't hashable, so they can't be used as e.g. dictionary keys, but typically that also simply makes a lot of sense: a tuple usually represents a record or a distinct "item", so it makes sense that it should be usable as a dictionary key because it's more or less a specific "thing", whereas a list can't be used as a dictionary key and this also typically makes sense: a list of a bunch of things as opposed to being something specific, so it's less sensical for it to be used as a key anyway.
nor does their use map to where you'd use an NSArray vs an NSMutableArray in ObjC
(FTFY)
Why wouldn't it? Again, so far as I can see, NSMutableArray is almost exactly identical to Python list in terms of semantics - maintains insertion order, O(1) access by index, amortized O(1) append. Ditto for NSArray/tuple. Admittedly I'm not an Obj-C expert, so I may not be familiar with some important pattern here that I am missing.
I'm not saying that you /couldn't/ use them in the same ways they are used in ObjC, just that that is not typically how they are used. NSMutableArray is almost exactly to a Python list in terms of semantics, but an NSArray does not map to a tuple in terms of how they get used most often in a Python program and vice versa.: in ObjC it's less common (as far as any ObjC code I've ever seen) for an NSArray to represent a simple record (with meaning of items implied by their position in the array), and it's relatively uncommon in Python programs to use tuples as a way to achieve immutability to "protect" an object or something. It might happen (sys.argv is the one case that comes to mind, but it's debatable that using a tuple was the right move there), but it's far less common than using a tuple as a lightweight record. For example, a function's args list (def foo(*args, **kwargs)) is a tuple less because of the desire to achieve immutability and more simply because the position of items matters.
The distinction between NSMutableArray and NSArray simply doesn't exist in Python (or Javascript or any number of other languages), and my assertion is that those languages aren't lacking in any way because of it (specifically, I mean that I have never, ever seen a case where not having that distinction has caused any problems). And because they are apparently not lacking (meaning: while problems could occur in theory, they don't ever seem to occur in practice), it begs the question as to whether or not making that distinction in ObjC/Cocoa/GNUstep actually adds any real world value (and my assertion is that it doesn't - it's all cost and no real world benefit).
Ok, so inherent in your reply is the assumption that I haven't spent time in things like functional programming or that I'm not aware of that stuff. Have you considered the possibility that I /have/ actually spent a lot of time both studying and using functional programming but have drawn a different conclusion than you?
The accidental mutation of objects is almost always a /theoretical/ set of problems - it just does not occur in practice unless you have some other problem (like not testing your code). Making containers mutable by default is not the same as giving license to any bit of code to mutate them - far from it. In, e.g. ObjC, whether or not a method mutates an object is denoted first and foremost by the contract the API provides - the description of the method, the documentation, the shared understanding of what the method does. The language-level enforcement is a distant second. In a language where the containers are mutable by default, that primary - and most important - contract remains in place. Because the secondary enforcement is such a distant second anyway, the lack of it doesn't suddenly introduce a whole new set of problems or anything. And that's the crux of my point: introducing an immutable container and then forcing that distinction to be made everywhere doesn't actually add any real-world value.
So, if I may, let me throw this back at you: what I find most ill-informed is your assumption that not providing immutable containers creates any real-world problems. You should really spend some time studying how other languages do this and manage to get by just fine. :)
Let's move this out of the theoretical space - can you help me see at least a /plausible/ example of a bit of code that would accidentally/unexpectedly mutate e.g. an array that wasn't intended to be mutated? Having never encountered this in practice despite using such languages for decades, I'm honestly having trouble coming up with something that isn't totally contrived. I mean, what we're talking about is essentially a function that (a) doesn't do what it is documented to do, and (b) most likely only mutates the object in rare cases (otherwise the very first time you used it you'd see that it is broken), right?
Method signatures are often ridiculously long (see NSBitmapRep's initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel: method)
Parameter names in method calls are /always/ named. You can't just say obj.someMethod(x,y). It's always [obj someMethodForX:x y:y].
The above combine to make even the most basic operations tedious. Want to trim leading/trailing whitespace off a string? Enjoy [someString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
I consider this an advantage. All those folks who talk about self-documenting method names finally have a place to hang their hats.
Yep, I recognize that some people like this and consider it an advantage. I don't - to me it just gets in the way of getting the job done and does nothing to increase readability since the variable names themselves will already convey nearly as much (or as much) meaning.
Immutable arrays, dictionaries, sets, strings. I get it, it can be useful for performance to know something is immutable (maybe, I'm not that convinced). But the common use case is most certainly mutable, so /that/ should be the default, e.g. NSArray should be mutable and then if needed there can exist some NSImmutableArray or something. But no, they did it the other way around.
Immutability is about more than just performance. Java and C# both have immutable strings. Good programming practice often recommends immutability as a way of enforcing contracts and avoiding unintended side effects. Some languages avoid mutability for any object.
Yeah, see the other posts on this sub-thread. Again, I understand that some consider the non-performance aspects an advantage, but I don't - I've never come across an instance where I thought to myself, "whew, thank goodness that object was immutable!".
I'm a strong proponent of duck typing and kin so I find language-level enforcement of mutability a nuisance. I understand the theoretical benefits of that type of enforcement, but again in practice find it more cost than benefit, and IMO depending on it is poor programming practice, i.e. if I'm being a good developer and writing good code and testing my code, then that sort of language-level enforcement does me no good whatsoever. If I'm being sloppy and/or not testing my code, then that sort of language-level enforcement isn't really going to be enough to save me.
it drives home the point of how absurd they can be.
No, it doesn't. In fact, it makes a very good case for Obj-C's syntax in situations where you have a large number of parameters.
I guess it's a matter of opinion. Variable names tend to be pretty descriptive, so having named parameters adds little value IMO, e.g. this sort of thing seems goofy to me:
[self drawAtX:x y:y z:z index:index]
whereas
self.drawAt(x,y,z,index)
is more readable (to me at least). Similarly, a method definition of
void drawAt(int x, int y, int z, int index)
is preferable to:
-(void)drawAt:(int)x y:(int)y z:(int)z index:(int)index
And the one example I cited was just for kicks since it's one of the longest, but message signature verbosity isn't uncommon in ObjC, e.g.
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
transitionFromViewController:toViewController:duration:options:animations:completion:
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
Since this isn't required by the language (though apparently encouraged by one of the largest backers of the language), I can't really fault ObjC /the language/ for this, but Cocoa is definitely guilty, and the redundancy in the variable names and parameter names /is/ IMO a flaw in the language - it just tends to make the source code noisy. Since code is read more than it is written, to me this is a real problem.
Code like the following is awful:
[self showQuestionAndAnswer:[[[SharedData sharedModel] attributes] answerID]
questionID:[[[SharedData sharedModel] attributes] questionID]
filterID: [[[SharedData sharedModel] attributes] filerID]];
Is it subjective to say that? You bet! But it's this sort of thing that makes ObjC sucky IMO.
We'll bring up the activity monitor and lo and behold Xcode is going nuts.
Ever try hitting the "sample process" button and seeing what's actually going on?
LOL, of course. I take it you're suggesting that that would reveal something I could then go fix??
See my reply elsewhere - several of my customers have analytics to back up their claims that a decent size of their user base is on 3.1.3 (iphone) or 3.2 (ipad).
While lists and tuples are both sequence types, semantically they are not Python's version of mutable and immutable list types, nor does their use map to where you'd use an NSArray vs an NSMutableArray in ObjC.
Sometimes. The hugest jump in improvement, by far, was ARC - and that support goes back to iOS 4 even though they introduced it with iOS 5. You can easily use that today, and have been able to really for a while now as there are very few iOS 3 devices around anymore.
Some of my customers and their analytics would disagree with you. :) (I can't drop
I think a lot of it comes from the inability to have any sort of mixin class.
What about categories!!!! Especially with the newer ability to also create variables local to them (which there have been means to do for awhile in different ways).
Thanks for the very thoughtful response.
You nailed it - the inability to add new variables w/o hackery was a big limiting factor such that we tend to use categories just for adding utility functions, e.g. to CGRect or something. I think categories with instance vars will help a lot once we can use them.
The single inheritance model and a strict class hierarchy discourages writing reusable code. For example, if I have an app that runs on iPad and iPhone and they share a common screen (from the user's perspective although the layout/design might be significantly different), it's a real task to write a common parent class holds the common code.
I find that protocols work better that multiple inheritance any day.
I don't. They have their place, sure, and the whole delegate model I think is a better fit than subclassing in /some/ cases, but in large part they seem aimed at solving two different sets of problems - protocols are often a good fit when you want to say that an object conforms to, well, a protocol, whereas a mixin class can be really useful when you just want to augment a class's functionality, perhaps for entirely internal purposes.
Similarly, there's no way to have a truly dynamic object with a clean syntax, e.g. in Python/ruby/js/and a host of others you could have a quick little object you use to pass state around, kind of like a struct that has its members added on the fly, e.g.: x = new Object() ; x.name = 'dave' ; x.age = 3. There is literally no way to do that in ObjC - the best you can do is create mutable dictionary and use its verbose syntax.
Well, it isn't impossible, but it does require some deeper knowledge. Objective-C has a concept called KVC, where you can refer to properties by strings, very useful stuff. There's also a mutable dictionary called the associationObject for each object. You could write the KVC reader to put the values into an assoiciated object, which incidentally is pretty much exactly what Python does internally.
Now, I'd question whether you really want to do this, but it's certainly possible. One thing I like about Obj-C is that things like categories, KVC, KVO, forwardInvocation, exchangeSelector, et al. are there if you really want to use them.
Use with caution, of course.
Sadly, I've tried all of that (it was actually for our Python-ObjC bridge in fact!). Care to show an example that doesn't result in tons of compiler warnings? I'll buy you a virtual milkshake if there's a way (and disabling warnings doesn't count, hehe).
I think you've missed the point I was trying to make.
No, I'm pretty sure I didn't. I just disagree with it. :)
When the array is local to your code, yes, it doesn't really matter if you start with it being mutable or immutable (unless you also do multithreading, but that's another story). The problem is at the API boundary of your code. If you declare a function accepting an NSMutableArray, it will only be able to accept that, and not an NSArray. If the caller only has an NSArray (because he obtained it from another API that returned that - which it did because it doesn't want anyone mutating that data), he now needs to do an explicit copy to make it mutable. Which is all a waste if your function doesn't actually need a mutable array, and only uses non-mutating operations on it. It's strictly better to make people declare the widest type possible at the API boundary, since it makes their code more generic.
It's definitely not 'strictly better'. Again, we might be talking past each other, but my point is that you're burdening people with a detail that they don't care about most of the time. In a programming language, that's a really, really big deal.
The argument for immutability seems to be couched in the desire to prevent accidents or something. If a function modifies an object you passed to it and you weren't expecting that to happen, what exactly are you doing? (i.e. did you misunderstand what the function does? Is the function buggy?) In all cases it seems like there are other issues going on, and having the language try to save you isn't really the right solution anyway.
I completely understand the notion that *if* your language or standard library distinguishes between mutable and immutable types, then using one over the other makes your API as generic as possible. I get it. I'm just saying that I don't think that distinction is very helpful most of the time, and yet by making that distinction you force people to worry about it even when they don't care.
Python has a very different story in that regard because of duck typing - you don't declare functions as taking lists, either mutable or immutable. You just work with an argument as if it were a list, and then it either implements the API surface that you need, or it does not.
That's exactly my point. Since we're talking somewhat about language design, I used that as an example of how this question of array mutability is not one inherent to programming languages, nor is the ObjC way clearly superior. Rather, it is a design decision that is a part of ObjC, one that I think has cost but little if any real-world benefit, and therefore a flaw in the language (again, it's subjective, but for my part it's a real flaw). The Python example was just to point out that other languages didn't see the need to burden the developer with it, and they get on quite nicely - i.e. to me it's a real world example of what would happen if you didn't introduce that distinction and it turns out that things work just fine without, which is why coming to ObjC from other languages it often feels like you have to do things because the language/library requires it, not because they are actually useful to you or the problem at hand.
NSBitmapRep's initWithBitmapDataPlanes:
I'm sure it's just a coincidence that the example you randomly plucked out of the air is in fact the longest method name in the entire Cocoa API
Haha, of course not - but it drives home the point of how absurd they can be. And while it's an extreme example it's also not /that/ extreme - there are quite a few that are very long, and a host that IMO qualify as "goofy long". I think explicitness /can/ be beneficial, but wanton verbosity is a net negative. As mentioned elsewhere, I recognize that this is subjective to a degree, but for me it is a real drawback to the language. I've used ObjC alongside other languages for years and strongly dislike the ObjC way, that's all.
You're a bit out of date here, and your code is probably incorrect (unless you did in fact intend to create a new root class). That should be:
LOL, yes, I've been severely punished for writing a snippet of code off the cuff like that, and I apologize. I am repentant and will try to avoid it, especially since it invites people to fixate on the minutiae while overlooking the larger point I was (apparently ineffectively) trying to make.
Xcode often pegs multiple CPUs when it's just sitting there
I've seen XCode use a lot of CPU while it's indexing a project I've just checked out. If you think it's not doing anything, check the status display and you'll probably see that it's not as idle as you've assumed.
I'm sure it's doing /something/, it's just not giving any hints as to what that is. The status display shows no activity, and the sudden jump is not typically tied to any user action that we can tell. We'll just be working in another app and notice the system becoming sluggish. We'll bring up the activity monitor and lo and behold Xcode is going nuts.
Haven't touched build settings, not doing anything 'silly', but I suppose that depends on your definition of silly. Here's just one example: in iOS on app startup, you shouldn't do very much in the initial method call into your app delegate as it is time sensitive, so if you want to do something around the time of init but perhaps before all the UI loads, then you might do e.g.:
[self performSelectorOnMainThread:@selector(biff:baz:) withObject:nil waitUntilDone:NO];*
No warning. The same was more common when UIKit could only be touched from the main thread. This is just one example, so to anyone who is itching to reply and say "you should use a different approach during app launch", let me pre-emptively suggest you're missing the point. ;-)
Immutable arrays, dictionaries, sets, strings. ...
There's a good reason for that, actually.
Well, a *reason* at least. Whether or not it's a good one is very debatable. :)
Immutable collection operations are a strict subset of mutable ones, which means that e.g. NSMutableArray is a subclass of NSArray. So, if someone declares a method that takes NSArray, you can pass an NSMutableArray to it - the method is generic in that sense.
Hmm.. the essence of this argument though is that it works this way because it was designed this way which, while true, doesn't affirm that the design was a good one. (More below)
On the other hand, if NSArray was mutable, and deriving from something like NSImmutableArray, then most people would likely forget about the latter, and use NSArray everywhere - including method signatures - even when they really only use the read-only part of the interface. The way it is now, it forces the person writing the API into a good habit: he'll write NSArray first because it's shorter, and will only change it to NSMutableArray when/if he actually needs some operation that's only available there. Thus, his functions will not be less generic than needed.
I think the key part of your statement is "most people would likely forget". And I think you're absolutely right, and I think that would actually be a *good* thing. A common problem with what I consider to be sucky programming languages is that they make the developer worry about things they just don't care about (see the other part of this thread, where we talk about prefixing string literals with '@'). 999 times out of a 1000, the developer doesn't care if a particular array is mutable or not, but the language makes them think about it - often earlier than they are ready to properly think about it as well. By itself, it's a tiny thing, but it's just this sort of thing that pervades ObjC/Cocoa (other languages are at fault too, but we're talking about ObjC).
The contract implicit in an API will always make it clear whether the object will be modified or not, so you really don't need the language to police it for you. For every one time it ends up helping you (because you were sleepy and ignored the docs or the function name or whatever), there's about a million times where it does /not/ help you. So you incur the cost every time but receive the benefit a statistically insignificant portion of the time.
Let me given you a counter example: in Python arrays are mutable. At several companies we've deployed all kinds of apps in Python - mobile, games, web backends, desktop apps, systems programming type apps, servers, etc. etc. - basically everything. (Note I'm not trying to argue the virtues of Python over your language of choice, just establishing that here's a language that has mutable arrays and we've used that language in a huge variety of apps and scenarios). Do you know how many times we've been bitten by the fact that we couldn't prevent a called function from modifying an array? Zero. Literally, as far back as I can remember (we started using Python in the late 90s) I can't think of a single case where this was a problem. Not a one. And yet in that time we used arrays thousands of times. What would have been the benefit of the language forcing us each time to specify the mutability of those arrays?
Method signatures are often ridiculously long (see NSBitmapRep's initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel: method)
That's rather the point. It make code easier to read and understand when you can see, in the method invocation itself, what all of the parameters are for.
Parameter names in method calls are /always/ named. You can't just say obj.someMethod(x,y). It's always [obj someMethodForX:x y:y].
Again, rather the point. Otherwise your above example would endue as initWithBitmapData(p,w,h,b,s,a,p,c,f,r,b).
I'll concede that this one is subjective, while stressing that for me it's one of the reasons the language sucks. :) I do understand the intent behind them, I feel quite strongly however that it makes for a cumbersome language to use.
The above combine to make even the most basic operations tedious. Want to trim leading/trailing whitespace off a string? Enjoy [someString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
Autocomplete makes this rather irrelevant, no? Especially the much improved autocomplete in Xcode4+.
Autocomplete helps, no doubt. And the newer autocomplete helps a lot. Coming from other languages though the net result feels like the language made something unnecessarily cumbersome and several revisions of the primary IDE of that language have done wonders at making up for it to a degree, without ever quite getting there completely.
Immutable arrays, dictionaries, sets, strings. I get it, it can be useful for performance to know something is immutable (maybe, I'm not that convinced). But the common use case is most certainly mutable, so /that/ should be the default, e.g. NSArray should be mutable and then if needed there can exist some NSImmutableArray or something. But no, they did it the other way around.
That you don't actually understand this point is pretty telling. Performance isn't the only reason to make arrays and such immutable by default. It also makes such structures safer to pass around, especially to outside code, without having to worry about the data getting modified unexpectedly.
Ah, the old "the language is protecting me" argument. It can have its place, but highly dynamic languages like Python or Ruby or C# or any number of others invalidate your point. That *you* don't understand this point is pretty telling. :)
Memory management (up until recently) was neither fully manual nor fully automatic and ownership was based on naming conventions
Ownership is always based on naming conventions, or else there would be no predictability and the language would be unusable.
Except for the fact that many other languages get by just fine without it. If ObjC would be "unusable" without it (which I don't believe would be the case), then that's just another flaw of ObjC and not programming languages in general.
Being a superset of C, they couldn't provide an object-oriented array class using the normal array syntax, so instead you have tedium like [myArray objectAtIndex:2]
"Fixed" in enhancements coming with Xcode 4.4.
I had a similar reaction when Java "fixed" this with syntactic sugar or whatever the solution was. These types of changes are unsettling to me because I'm at least somewhat aware of the tricks needed to pull it off. When any complex system like a programming language and compiler and runtime, you get cruft built up over time, so a language having to bolt on something so fundamental makes me doubt the longevity of the language - undoubtedly there will be unintended side effects or unfo
Technically these days you just need one thing, the @property. You don't need anything else. Hard to get less redundant than one definition.
On iOS, you never need the ivar that you put in, so that's needlessly redundant. That's user error, not a language issue. That reduces you to three required references at worst. The property, the synthesize, and the dealloc reference. New LLVM makes the synthesize go away, older LLVM with ARC killed the dealloc reference. So these days you're down to 1 line of code.
*If* you have the luxury of being able to use all of the latest and greatest features, that can be the case, yes. That's very often not the case though. But yes, you make a valid point.
Like I said, you don't seem to have a firm understanding, which is kind of dangerous when critique a language that you don't really know. I took two years of Spanish in high school, doesn't put me in a position to claim I understand Spanish and it's a horrible language.
Well, let's run with that example: "two years" of Spanish typically means "5 hours of sitting in a class and some homework each week, for 9 months, then a 3 month break, repeated", which is incredibly different from, say, living in Argentina by yourself for the same amount of calendar time. With the former you end up with at best a superficial handle on the basics of the language, while in the latter you can achieve a really good degree of fluency.
If you are developing code in a language day in and day out for a couple of years, that's close to the latter, and it's plenty of time to understand quite a bit about the language. More to the point of this whole thread, however, in far less time you can come to have a very good feel for how that language compares to others. While you and others have made some very legitimate points about a few individual places where I'm still using old-fashioned ObjC or where in my haste I failed to run a jotted down snippet of code through a mental compiler, my takeaway from all of this is that ObjC is incrementally less lousy than I thought. So far nothing there's little to suggest that fixes to ObjC have significantly closed the gap relative to more modern alternatives.
I understand all of what you're saying, merely pointing out that the compiler still issues some warnings that, according to your reasoning, it should not. In some cases it already generates a warning when you use a selector it doesn't recognize (e.g. [ someMessage], or [self someMethodDefinedAfterThisOneAndNotDeclaredInTheInterface]).
You have a property, why are you making a class var?
I'll readily concede that it's habit mostly - because IIRC pre-64-bit Mac we had to. :) Obviously I'm catching a lot of grief because I wrote a couple of quick lines into a post without really proofing it, writing it more as a "you know what I mean" than a "this is precisely the way to do it". I appreciate everyone's right to do this (and it's a long part of the /. tradition) but to me it's a case of not seeing the forest for the trees. As mentioned elsewhere, the cumbersome nature of ObjC is most noticeable to me when I have to hop back and forth between it and pretty much any other language we use on any project. So, yes, while there are some flaws in what I typed into ye olde form element, I think it's overshadowing the point of just how much /work/ it is to write code in ObjC compared to many other languages.
Now, I don't have a whole lot of data, so consider this purely anecdotal, but this is what I have found to be universally true: people who use ObjC and also program a lot in other languages tend to dislike ObjC, while people who really like ObjC don't tend to be as broad in their use of languages. Both sides can draw their own conclusion from that. :) For me, if I'm working on something else and then hop in to ObjC for a bit, it feels exactly like going back to assembly did back in the day when we finally transitioned to C for most everything: once we had gotten used to the higher level nature of C, dipping into assembly felt archaic. Those who still swore by assembly hadn't really spent much time in other pastures, and would extol the virtues of modern macro assemblers and other new features.
Those are just the kinds of things that make people who have been working with ObjC a long time think of developers new to the language, or at least not spending any time keeping up...
That's a fair point, although I would make a minor counterpoint that there is often a long time between when a new feature becomes available and when it becomes usable in practice due to the need to support legacy projects and code, so I think it's somewhat expected to discount some of the new features to a language (granted, I know these specific ones were added in what Apple calls the 'modern runtime' or some such, but still there are features like ARC and on some projects blocks that are still unusable to me due to legacy needs).
not to mention the complaint about delayed selectors, they are often abused by people who don't really understand why something doesn't work and just pushes the code out to a delayed call
Well, I couldn't really say whether or not other developers use them, nor does their abuse imply that they are bad - they are a standard feature and legitimate to use my frustration with them still holds. :)
Your whole post was valid perhaps two years ago, but there are not many items you are complaining about that are real issues anymore
... if we can use the latest and greatest features, which is often not the case. It's great that these warts are being fixed, but given the choice I'd much rather just choose a more modern language that didn't have them in the first place. Perhaps that's part of the root of it all for me - the unique features of ObjC provide very little in terms of benefits over other choices available today. If it weren't the "standard" language for Mac/iOS development I'd never touch it again.
I do exactly the thing you mentioned (a common base class that is reused between iPhone/iPad instances of those classes) and have not found that to be a problem. What do you feel is limiting in that regard?
I think a lot of it comes from the inability to have any sort of mixin class. It's common for us to need e.g. a bunch of similar functionality on multiple iPhone screens, suc
It's more than just text completion: you have to remember enough to even get started. I've been programming in ObjC for years and sometimes still have a Monday morning brain fart trying to remember stuff, especially if I'm working on a project that involves hopping between multiple programming languages. Want to split a string into its comma-separated parts? Is it 'parts'? 'items'? Ah, no, it's [NSArray componentsSeparatedByString:].
As implied above, if you're writing in ObjC then most likely you're writing for Mac/iOS (I'm ignoring the sliver of people using GNUstep). Every 8 or 9 months I try ditching Xcode (I use Vim for all other development) and even once you get the autocompletion set up for Cocoa (not an easy task), it never works quite right.
One other thing to keep in mind is that the interaction for autocompletion in ObjC isn't the same as what you'd find in e.g. C, there are a few additional wrinkles. For example, if a parameter is actually a message send to another object (e.g. [foo call:[otherObj bar]]) and you don't put that 2nd bracket in there, the code completer often gets confused and puts it in the wrong place. Moving between parameters is a bigger visual jump since every parameter is named. There are a few things like this that make autocompletion a much more complex experience for the developer than what you'd find in other languages. Is it a huge burden? No, but it's just one more layer of annoying.
Well, I think the point still stands, especially considering that the code for that example is split across two files (the .h and the .m) - i.e. the language is needlessly verbose even with a few minor improvements (i.e. not using self.title= doesn't reduce the number of lines of code, for example, and not needing a backing ivar chops off a couple of lines, but it glosses over the large point of why on earth any of that should be needed in the first place. It's 2012 for crying out loud.).
That's great that it can be less redundant now, but going from 4 mentions of a variable to 2 or 3 just before you can do anything with it means the developer is still doing stuff for the language, and not the other way around - i.e. the language design flaw remains, even if partially covered by a band-aid. And I think that kind of gets to the larger issue: given that there are so many available languages today, I'd rather choose something that is fundamentally cleaner over one that has a bunch of junk bolted on in an attempt to keep the language relevant.
That's irrelevant - the compiler could at least issue a warning when you're using the selector literal syntax. It's no different than the compiler issuing a warning when you send a message to an object using a selector that may not exist even though that too could be valid at runtime.
In my mind it's two-fold, really:
- Maybe it's a generational thing for languages, but once you take OOP features onto C in an attempt to modernize it, then you naturally are going to think about using it in places where you would use some higher level, more modern language, or at least compare it to the features of higher level, more modern languages. In this respect ObjC falls down, and IMO, rather badly. Then again, C++ does too, so I guess it's in good company. There are so many other choices out there that don't get in the way as much. This may sound goofy, but C is just C - it's not pretentious and pretending to be a Java or a C# or whatever. It's just C and so going into it you just approach development a little differently, and that approach has worked pretty well and remained steady for the past 25 years (probably longer, but I don't have any experience with it farther back).
- Most development - in any language - involves more than just the language. It's also using a standard library and any number of add on libraries. I'm fairly confident that a relatively small number of people use ObjC outside of Cocoa on iOS and Mac OS X, and even fewer outside of the group of people that use either Cocoa or GNUstep or whatever it's called. Because those libraries are written to use e.g. the ObjC message sending syntax and object life cycle semantics, in practice if you use ObjC then you are very likely going to be using the ObjC language features (i.e. the fact that you /could/ write your app all in straight C is irrelevant since (a) you couldn't call the Cocoa libraries and (b) if you did that, you wouldn't be using ObjC probably anyway). So, yes, the extra features /do/ in fact degrade what was there in the first place. A classic example would be an array. If you took all of the ObjC programs out there and looked at all the cases where arrays were used, I'm willing to bet that the overwhelming majority of the cases don't use a C array but instead use an NSArray. The latter is somewhat more powerful but unfortunately incredibly cumbersome to use relative to a good ol' C array. In theory the old C array is there, but in practice it largely isn't.
Honestly, from your example code, it certainly looks like you've worked with Obj-C, but it doesn't look like you really had a strong understanding of it. Not that I don't blame you, with Obj-C 2.0 it became a little harder to understand, but Apple is cleaning that up.
LOL, you deduced that from a couple of lines of code hurriedly typed into a web form? Gimme a break. I could just as easily say something like, "based on your reply, it looks like you've worked with Obj-C, but not much else; you haven't been exposed to enough development to see the weaknesses in your language of choice or appreciate the value of the alternatives." (I'm not saying this is the case, but see how it comes across?)
Thanks for your reply though.
(replying to myself) By iOS I should have said iOS and Mac OS X of course.