Comparing python to C …
Well, I’m about 1/2 done with adding multi-players to Galcon-iphone. I figured I’d stop for five minutes and note down some things I noticed during my porting experience. Obviously, C and python are different, but here are a few of the ways I’ve FELT the difference.
- C doesn’t have garbage collection. I’ve managed to avoid doing much manual GC by having everything in a single big struct that keeps the entire state. The only place I use malloc/free is when I’m downloading web data. So it hasn’t been a big deal for this project.
- Speaking of web data, C doesn’t have a built in urllib. I wrote my own awful HTTP 1.0 page fetcher. On the plus side, I was able to make it work *exactly* how I wanted it. No threads, non-blocking 🙂
- Although not “built in” I found enet, which was a thin layer above UDP for networking. I found this incredibly much easier to use than python sockets were. (Yes, I could have used some other python lib, but I didn’t.)
- C is really fast. Thankfully, since I originally dev’d Galcon in python, I was “forced” to get my algorithms pretty good to keep the speed reasonable. By porting everything to C, I’ve now got amazing speed. I think I could host 100+ servers on a single CPU easily.
- Managing strings in C is an ordeal. It’s just not pretty, so I try to avoid doing much with them.
- OpenGL seems pretty painless in C. I haven’t done any notable OpenGL stuff in python, so I can’t really compare the two.
- No exception handling makes me have to code things more carefully. In python, I could parse an incoming networking packet, and just wrap it in a “try: (parse stuff) except: pass” block. If something was bad about the packet, it would just move on. In C, I have to check everything carefully so that I don’t create some kind of segfault by accident.
- In my case, serializing data is easy in C. I can just save a structure to a file (or send it in a net packet) and load it back later. In python this is much more complicated. (Especially since Galcon-shareware isn’t pure-python.)
- By using C, I don’t have to deal with some awful FFI. That is a HUGE time-saver.
- I must admit, I LOVE python’s indents. But I also must admit, now that I’m back into C coding, I don’t miss them as much as I thought I would.
- I still dislike header files. I wish C magically generated them or something instead of making me write them.
- I learned about writing tests in python. I’m doing that in C for my networking code. I run the tests as part of my build process, and it saves loads of time by catching all the bugs for me 🙂
- Automatic type checking is sort of nice. Having the compiler tell me I didn’t do anything incredibly stupid is sort of nice. (Although in some cases, it can get a bit annoying.)
Well, that’s about all I can think of for now. Draw your own conclusions.
August 6th, 2008 at 3:44 am
“In my case, serializing data is easy in C. I can just save a structure to a file (or send it in a net packet) and load it back later.”
Be careful on that one. You’re relying on undefined behavior here. Future versions of the compiler could rearrange the structs in a different order or with different padding. Not to mention that the next iPhone might have a different byte-order. 🙂
Proper serialization in C is a lot of work…
August 6th, 2008 at 5:32 am
Hi Phil,
If you want “try/catch/except” in C, just rename the file (or files) to .m and you will able to use the objective-c’s @try / @catch / @finally statements.
I didn’t try catching a segfault exception but I think it is possible (although I don’t recommend it).
August 6th, 2008 at 5:51 am
Welcome to low-level programming 😛
August 6th, 2008 at 8:11 am
I highly recommend libcurl as a replacement for urllib and your hand-rolled solution. Mature code, works everywhere, liberal license (MIT/X11), thread-safe, simple, and widely used.
August 6th, 2008 at 8:23 am
“By using C, I don’t have to deal with some awful FFI. That is a HUGE time-saver.”
What’s an FFI?
August 6th, 2008 at 8:25 am
Foreign Function Interface .. a means for accessing C functions from a higher level language. Within C it’s not really an issue 🙂
August 6th, 2008 at 8:55 am
“In my case, serializing data is easy in C. I can just save a structure to a file (or send it in a net packet) and load it back later. In python this is much more complicated. ”
What’s wrong with Python’s Pickle? I would argue that it’s about as easy (and safe) as it gets, when it comes to serializing data. Of course, we could all be using Google’s Proto Buffers or Facebook’s Thrift.
August 6th, 2008 at 8:58 am
Greg: http://en.wikipedia.org/wiki/Foreign_function_interface
August 6th, 2008 at 9:00 am
Nothing really. pickle isn’t very secure either, actually … But in my particular case (Galcon) the challenge in my python implementation that I have much of my game state stored in C (all the ships). So serializing that data would be somewhat problematic.
As for the struct padding, etc. Thankfully I’ve been able to avoid that issue. It appears that linux and the ipod have all those things the same, so the net transfers work fine. If at some point that becomes NOT the case, I’ll have to deal with it. I was also glad that endian issues didn’t crop up either.
August 6th, 2008 at 10:49 am
yes, and in case you start having problems with “padding” in the structures, use:
#pragma pack(0)
August 6th, 2008 at 11:46 am
In my experience OpenGL in C and in Python using Pyglet is about the same. The main difference is that in C when I’m pushing and popping a lot of matrices I can indent to indicate a push and that really doesn’t work so well in Python.
August 6th, 2008 at 11:55 am
I really like header file. I think they “tidy up” the C/C++ code. In the header file you read immediately classes/functions. In Python you *must* have a good IDE that shows you classes/functions.
August 6th, 2008 at 11:55 am
Not directly related to this post…
On the 8/1/08 episode of “1UP Yours,” a gaming podcast on Ziff-Davis’ 1UP Network, they briefly discussed GalCon for the iPhone, mentioning that it’s one of the few games on the phone worth playing. Thought you might be interested.
Homepage: http://www.1up.com/do/minisite?cId=3149993
Link to that show: http://www.podtrac.com/pts/redirect.mp3?http://download.gamevideos.com/Podcasts/080108.mp3
August 8th, 2008 at 5:11 am
Um, why the heck aren’t you writing in Objective-C? Sorry to be so harsh, but almost all of your complaints would have been addressed by moving up an abstraction to ObjC, including especially the memory management (which is very efficient and painless in ObjC, even though it doesn’t have GC), non-blocking, non-threaded URL library (NSURLConnection), string handling (NSString), exceptions, and data serialization to disk (NSCoder/NSArchiver); but you’d still get all the advantages of using C (No FFI, almost as fast as assembler, strict type checking).
Learning a new language would probably have been less of a hassle than all the extra code you have to write when coding in C.
Also, I reviewed Galcon-iPhone on my site: http://iphone-reviews.tumblr.com/post/44474643/galcon-phil-hassey-perfectly-suited-for-the-iphone
August 8th, 2008 at 8:02 am
@Joachim – that’s a reasonable question. I guess the reasons I had when I decided to go with C instead of ObjC were:
– I didn’t want to, I already knew C.
– the code examples I saw looked more verbose than what I could do in C, so that turned me off from it.
– I didn’t know anyone who knew ObjC who could hold my hand.\
– I didn’t want to depend on the iPhone APIs so my code could be built under Linux / Windows.
So no really great reasons, other than, ObjC just didn’t entice me enough to want to actually learn it.
August 8th, 2008 at 8:49 am
I hope you don’t mind me rebutting 🙂
– C style coding is terse, but on the other hand, you have to write a lot of blanket code, both because of the language itself (e g “int i = 0; for(; i < someLength; i++)” vs “for(obj in collection)” and because the standard library is so small. Also, I like Cocoa’s verbosity, because it lends to self-documenting code (a method’s complete functionality is in its name, rarely with non-obvious side effects).
– If you wish to do code in ObjC/Cocoa in the future, I’d love to help out, just contact me 🙂 I love the language, can’t stop evangelizing it 😛
– You already got Python for desktop OS’s 😉 Yeah, I know, speed…
August 8th, 2008 at 8:53 am
No problem. While we’re on the subject – one thing that I noticed which made me very nervous about ObjC is that it seemed to me that there were at least 3 different String objects that I came across.
For a “noob” to ObjC, that’s scary as all get out. Which string do I use? Why are there 3? Should I be concerned? Is there some real difference? etc …
The speed thing is actually really nice, I’m going to be able to host dozens of servers on a single CPU 🙂 Which will be great if the MP game takes off.
August 8th, 2008 at 9:31 am
I’ll gladly explain 🙂 It boils down to different abstraction layers. At the bottom of user space you have Core Foundation, which serves as a common ground for the higher-level APIs above it. It’s plain C, and it provides, among others, CFString. You can use this from your current C code to clean string handling up if you feel you need it 🙂
Above that, on a desktop Mac, you have several APIs, e g Cocoa, Carbon and Java, that all have wrappers around CFString. In Cocoa, and on the iPhone, Cocoa Touch, you have NSString, which is an ObjC wrapper around CFString.
CFString and NSString are toll-free bridged, which means that you can send a pointer to the one to a function requesting a pointer to the other (i e, doing (CFString*)myNSStringInstance is okay) (e g if you want to propagate an NSString down to your C code without copying and/or degrading it to a char buffer).
I’m guessing that the third string you found was NSMutableString. The distinction is that an NSString (and almost all other container class bases in Cocoa) is immutable (like const), for performance, and so that you can share one instance in many places without having to worry about it changing under you (sharing instances is an area where ObjC shines, for being a C language). Thus, if you want a string which you can change in-place, you’d use NSMutableString.
Then there’s also NSAttributedString, which is for styled text.
If you want a book on ObjC/Cocoa, I’d recommend Aaron Hillegass’ “Cocoa Programming for Mac OS X”. It’s probably the best programming book or maybe even computing book I’ve read.
For networking and high performance servers I’m learning Erlang, a distributed concurrent language, and it’s really cool, stable and fast 🙂
August 11th, 2008 at 11:42 am
Heh, yeah. Read a book, spend weeks on end studding and learning new languages and API’s, or hack it in and move on to the next project.
Hmmm…
August 12th, 2008 at 6:57 pm
This also shows that domain knowledge always trumps any advantages you get from languages.
It also shows that using a good library can speed up development more than using a higher level language too.
If your program can already scale like Phils can, you really don’t need erlang. It’s easier to just keep adding servers. Since each server only allows say 8 people at once to join it… there’s only that shared state.
August 12th, 2008 at 8:14 pm
I would have used curl (I considered it) but it’s bigness scared me. Though I probably would have broke even / saved time if I had bothered to work it out. Maybe next time 🙂
I did use enet and some md5 lib though. Those saved huge amounts of time.
August 21st, 2008 at 10:14 am
Why not write a python script to generate your header files from the .c files? It’s really quite simple – put the structs and any includes etc in a comment block at the top of the .c file to be read in for the .h file, then parse your file for functions if it has changed and put declarations into the .h file.
I do something similar with Objective C and it works well – no longer have to worry about putting declarations in by hand.
August 22nd, 2008 at 7:39 am
PoV: Evolve a single skill as far as you can get, or shift your entire way of thinking about the skill by learning a new (good) language/library? I guess you could argue for the former, but I prefer the latter 🙂
September 11th, 2008 at 7:28 am
Does this mean you’re re-writing the linux version => no more need for python2.4?! The increased speed would be very welcome. I hate the fact my machine stutters with 2 cpu players and me… it’s not that old! 🙁
September 11th, 2008 at 7:29 am
Yeah, I got excited and was expecting a title box… 😛