Tuesday, June 26, 2012

Warning Level 4

I became a better programmer recently.  Very recently in fact.  It happened the second I finished C++ Coding Standards by Herb Sutter and Andrei Alexandrescu (Not Alexander Andreiscu as I keep forgetting!)  Two brilliant people who I will one day match!  I hope.

I've always loved picturing learning programming as a constant wave between thinking you know nothing to thinking you know everything and back again.  This book gave me about a dozen full 'waves' as it told me what I didn't know and then taught me it.  Besides that it also pushed good Coding Standards which I'll strive to meet.  The obvious one from the title, is warning level 4, warnings as errors.  It touches on a lot of things you know you should do and then presents the (very compelling) reasons why you should do it.

A few things that really stood out to me:

Item 30.  Avoid overloading &&, || and , (comma)

I probably should have known that the order of operations would be lost.  But it's really easy to assume they'll be kept.  This was a really good fact to pick up, especially considering I've been programming in Scala a fair bit (I love that language) in which you can take advantage of order of operation in operator overloading.

Item 44.  Prefer writing nonmember nonfriend functions.

This isn't something that came as a shock but, the arguments for it really stood out to me.  I'm still a student and as a student I've been told that objects are awesome.  Use objects.  Everything should be in a class (okay, maybe not that far but definitely far enough to assume that last one.)  I'll admit that one of that bad things I've always done is keeping operator overloads that should be nonmember functions in the class.  I always thought it made more sense.  I knew I shouldn't do it but, I always figured I'd wait until the next project to start doing it correctly.  Well, the next project starts now, and those operators (along with a bunch of other functions) are being taken out of the class.

Item 49.  Avoid calling virtual functions in constructors and destructors.

Because they aren't virtual there... Whaaat?  Now, I don't think this is something I've ever done (or thought of doing for that matter.)  But if I did, I definitely wouldn't have expected that.  And pure virtual functions cause undefined behaviour.  Feels a bit minefield-y.  One of the solutions is a factory function, definitely going to be my approach in the future!

Items 92- 95. Cast wisely

These were the ones that really changed the way I look at what I was taught.  For instance, I was taught to use C-style casts on pointers.  This is bad.  Don't do this.  There are three (four including const) casts that are possible.

dynamic_cast<NewType>(object) is the safest and will never be used by C-style casts.  It performs safety checks at compile time and run time.  It does incur an overhead but, one should not optimize prematurely.  Use it as much as you can.  Worst come to worst, it's easy to write a function that will use dynamic cast only in debug.  If the cast fails it returns a null pointer.

static_cast<NewType>(object) is the second safest and is at least portable.  It has no runtime overhead.  Aside from that it is very like dynamic_cast.

reinterpret_cast<NewType>(object) is not for everyday programming (depending on what you do everyday, I suppose.)  In short, it's functionality is implementation specific.  It's unsafe, unreliable and can result in crashes and undefined behaviour.

As stated on http://www.cplusplus.com/doc/tutorial/typecasting/ :
"The conversions that can be performed by reinterpret_cast but not by static_cast have no specific uses in C++ are low-level operations, whose interpretation results in code which is generally system-specific, and thus non-portable."


 So basically, you don't need it unless you know exactly what it's doing.

Now how does this relate to C-style casts?

Well

#include "Derived.h"
void fun(Base* base){
  Derived * myDerived = (Derived*) base;
}

and

#include "Base.h"
class Derived;
void fun(Base * base){
  Derived * myDerived = (Derived*) base;
}

Are completely different.  The first will use a static_cast and everything will be okay (if you pass in a Derived* to base).  The second will use reinterpret_cast and, as we now know, reinterpret_cast should not be used here.  Why is it used?  Because the compiler has no idea that Derived is Derived from Base, it just knows that it's a class.  This becomes a huge problem when multiple inheritance is used as it could result in a pointer of type Base2 pointing at the Base1 implementation in Derived.

There are tons of other create points in the book and I recommend it to everybody.  If anybody notices anything wrong in this post please point it out.

Quick note, I understand that reinterpret_cast is useful for somethings, the book realizes this as well and provides Exceptions for almost all of the Items.

Monday, June 11, 2012

A Return

It's been way too long since I posted anything here.  It's come to my attention that a professional presence on the web is going to be a boon and so, this is my start.  I'll probably be migrating to a more appropriate website set up but, this will do for now.

Update

UDK
I've programmed quite a bit of UDK since my last post, having joined a team working on a game called Game Wizards.  The game is looking good and I hope to have a link to a trailer up soon.

It was a great experience.  Most of the programming was done in unrealscript which looks to become deprecated over the next few years.  I'm torn on how I feel about this.  

Unrealscript was a poorly designed language.  I get the impression that it was created with designers in mind, much of the language indicates this (such as the indefensible case insensitivity) but, it ended up being used for tasks it shouldn't have been used for. Unrealscript made it easy for designers to change behaviour using default properties.  Near every other point where unrealscript diverged from traditional languages was a detriment.  I'll not miss the language at all.

That said, I am somewhat sad to see something I so recently learned possibly becoming irrelevant in a few short years.  The experience with working with such a large code base (as we extended mainly from UT functionality) will serve me well, though.

Templates
Another place where I've spent much of the past months is working on templates.  I don't have the experience in the game industry in order to tell if they're underused but, I believe they present a great opportunity for optimization of runtime performance if they can be properly applied to games.  Few areas of software development prioritize runtime performance more than the game industry and so I hope to spend some time doing some research into the application of templates in games.

As is, I created a simple linear algebra math library utilizing them.  It was a rushed implementation and is definitely not breaking any ground other libraries haven't already broken.  That said, the experience was extremely interesting and enlightening.

Shaders
Graphics in particular has become extremely interesting to me.  I did a few shaders (fresnel lighting, bloom post processing effect) and found them very interesting.  The openGL framework I created to run them was an educational experience as well.  It's use is very different from traditional C++ libraries due to it's C background.  I plan on using the framework to implement examples from GPU gems.


I've done a lot of work besides this over the past while but these were the recent highlights.  Look forward to posting more frequently with much more interesting points.