Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,671
6,212
The project I'm working on right now requires messages be exchanged between a client, an iOS app written in Obj-C, and a server, written in Python.

I needed to write code that escaped messages being sent between the two, which required me to write an identical string encoding method for both of them.

Here's the Python implementation:
Code:
    def encodeName(rawFilename):
        return '|' + re.sub('|', '/|', re.sub('/', '//', rawFilename)) + '|'

It's pretty easy to read (I have comments that explain what it does and gives example input/output despite that) and it follows my rule of not having lines longer than 80 columns.

Then there's the Obj-C implementation:

Code:
NSString *encodeName(NSString *rawFilename) {
    NSString *halfEscaped = [rawFilename stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
    NSString *fullEscaped = [halfEscaped stringByReplacingOccurrencesOfString:@"|" withString:@"/|"];
    return [NSString stringWithFormat:@"|%@|", fullEscaped];
}

It seems to me that the important parts of my code are now buried and lost (what's getting replaced by what in what?) How things are related is now lost (it was obvious in the Python code that everything was wrapped in pipes - now you have to look to the final line to see something is wrapped in pipes, and work your way back to realize that fullEscaped is everything else.)

Plus the lines are too long, leaving me with one of two options:
1 - I could wrap, and have @"//" be right under @"/" and @"/|" be right under @"|", although the line will still be over 80 characters long in this case. Plus it looks ugly as sin.
2 - I could just violate my rule and require scanning across lines.

Of course, I could solve my problem by just writing a sub function in C, which internally uses stringByReplacingOccurrencesOfString:withString:, but occupies 3 columns instead of 47 columns with the name of the function.

Heck, I'm thinking about that name right now - it SUCKS. The world string is used thrice in the name and it conveys absolutely nothing each time. This name would convey the same amount of information, be easier to read, and take up fewer columns:

replaceOccurrencesOf:with:

I suppose I might be misplacing my blame. Obj-C has plenty of flaws (@selector(method: )? They honestly couldn't come up with any better way of passing selectors around?) but this post mostly laments how terrible the built in NS classes are... so it's more about the standard Obj-C library than the language itself.
 
Oooooooookay.

Well, I find the Objective C version readable. I have no idea what the Python version is, "sub" doesn't tell me anything in particular (substitute? subtract?). Operator overloading is and always has been lame, so there's that too.

It took me all of two seconds to figure out what the ObjC version was doing. To each his own, I guess.

-SC
 
Will have to strongly disagree with you on this one.

The Objective C code is self documenting, anyone can understand exactly what it does immediately.

The Python snippet is dirty one-line magic. I understand what it does but I will have to look at it for a bit longer. If you have been coding a whole day this is where you can easily introduce bugs. You should at least split this into multiple lines for added readability. The fact that you feel the need to comment such a simple operation speaks for itself - it's too complicated.

The 80 column line width, who does that anymore??? Surely you just end up with stupidly short variable names where you have to add comments to explain what they are?
 
I completely agree with everyone else here.
Just because your code is compact, fits on online, doesn't mean it's "good" code.
I find if you're going to document that one liner, then you might as well write it in two lines anyway.
 
I guess I fall somewhere in the middle.

Even with my very light exposure to Python, I immediately saw the ‘re' and assumed Reg Expression, and the pattern of value, value, string looked like most substitutes in languages outside of Obj-C (but that’s speaking from a decent amount of experience, across multiple langs), but it definitely a bit eye-crossing (using a return re value for a param in a nestled re).

The Obj-C is very self describing, but the syntax very lengthy with the named params - the worst part is the string concat methods (finally, Swift has a nice clean concat operation).

(It’s also an RE vs. a string.replacement type function, vs. both using RE)

So I guess it depends on your experience, how much brevity you like in your code, whether the minimally-meta syntax results in just as much work because of needing tons of comments.

I find the Python a bit terse, the Obj-C a bit verbose.
 
(It’s also an RE vs. a string.replacement type function, vs. both using RE)

It's a regular expression that only contains literal strings so it amounts to the exact same thing as string replacement.

Obj-C's regular expressions... It gives me the chills when I have to use, read, or debug those. I have plenty of categories to shorten them and improve their readability.
 
The 80 column line width, who does that anymore??? Surely you just end up with stupidly short variable names where you have to add comments to explain what they are?

Please Refer to PEP 8, Maximum Line Length.

I realize that PEPs are specifically written with Python in mind, but the same arguments can be made in any other language. PEP 8 should be required reading for anyone writing Python, and I recommend it to anyone writing code in any language.

One convention that a CS professor had for his class that I've been thinking about is that if you can't get everything to fit on one line, you should break it all up onto multiple lines. We were using a Lisp language in his class, and the convention really helped improve the readability of Lisp code. I can't tell whether I like applying the same rule to other languages, like Obj-C, or not.

IE, the following are okay according to his rules:
Code:
[method thing:var thing:var thing:var]
[method thing:var
        thing:var
        thing:var]

But these aren't okay according to his rules:
Code:
[method thing:var thing:var
        thing:var]
[method thing:var
        thing:var thing:var]

Where this falls apart is when you have a method that's taking 5+ arguments. Then again, maybe having a method take that many arguments is an indicator that you need to refactor some how... either the function does too much or you need a layer of abstraction that groups some of the arguments together, such as a struct or class.
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.