Saturday, April 14, 2012

#12 April 15th

The final project has been announced - it's the famous Conway's game of Life. It would be interesting to have glider guns as one of the input cases. It's also interesting to have another evolutionary-style project handed to us after Darwin. This one again, is solidly suited for object-oriented design and I suspect the first half of the semester was prepping us to get comfortable with the eccentricities of C++ so that we could tackle these with a lot of tools under our belts. This one also makes use of abstract classes and inheritance to reuse code, something which I have wanted to hone - and even if it's just one project, I appreciate that this is being thrown at us as part of the problem. I'm really looking forward to solving this one, but I need to get hold of a partner first! So, more on "Life experiences" later.

As for the material covered this week - we went through copy assignment in Java and C++ using a Complex class example. We also started on inheritance. Some of the interesting things that came out of this week's lectures are:

  • In a constructor's initialization list, the order of variables is immaterial. Initialization of variables occurs in the order that the variables have been declared in the class.
  • You can access private members of an object if it is the same type as yourself.
  • A non-static const method CAN modify static data
  • delete 0 is well defined to do nothing
  • The Rule of Three comes in to the picture when you're writing a class that has to perform explicit memory management (say you're writing the vector class and need to manage the underlying array). It states that: "If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them." Something important to keep in mind! See this StackOverflow article for the full story on copying objects.

Sunday, April 8, 2012

#11 April 8th

I feel like a marathon runner entering the final few laps. There's 3 more weeks to go - so it's time to buckle up and get this thing done well.

This week had a diverse range of topics. We covered static and instance methods in both Java and C++. We also touched upon friends in C++. One interesting thing in that discussion was the following:

Say you have a templated global function:

template <typename T>
int f();


Then, if you want to declare all instances of it as a friend in one of your classes, the syntax is:

template<typename U>
friend int f(); //Notice the U is not used


However if you have another templated class C which contains f(), and you want all instances of C's f() to be friends with your class, then the syntax changes to:

template<typename U>
friend int C<U>::f();


Another new thing that I learned was the explicit keyword. Since C++ allows implicit conversions of the parameters while constructing objects, if the class Foo had a constructor with a single int argument, ordinarily it would allow something like:

Foo f = 2;

However, as you can imagine, this is a slippery slope towards a landmine of bugs (interesting visualization, eh). If that constructor was now declared as explicit, then the line would not compile anymore.

One final bit of trivia to end this post - one can overload member functions (class methods) not simply by changing the number and/or type of arguments, but also by changing the constness of that method.


Sunday, April 1, 2012

#10 April 1st

It seems like I should write something witty given that it's April Fool's day, but I'm just too tired. This week has definitely been a learning experience. I was not aware of the tremendous variety with which variables could be declared and/ or initialized in C++. I know it sounds like a trivial thing, but it's not.

A case in point: We are working on the Darwin problem, which you can find more about here. This is, refreshingly, a problem which begs the OOP paradigm. So we made a Creature class to represent the different creatures in the world. Now the thing is, every Creature needs to have a reference to the Darwin world it belongs to. This is so that it can ask its world - "hey is there a wall ahead of me?" and other such useful questions. All of them need to have the same reference - so it's obvious that an externally created Darwin object must be passed to each Creature and stored as a const reference. However, in C++ you cannot initialize reference variables in the body of your constructor! And you definitely need to have it initialized since it's a reference variable, for crying out loud! Initialization lists come to the rescue. The initialization lists run before the constructors are called and can therefore initialize any member reference variables you may have declared.

That's not where the idiosyncrasies end. Have a static member variable in your class, do ya?! Well you can't initialize it in there. You MUST redeclare and intialize it outside the class in the form:

Type ClassName::staticMember = value;

Rather annoying!

An interesting list of other facts I learnt is:

  • Local static variables get initialized only once and consequent initializations don't throw an error, they are simply ignored. Thus they can be considered as global variables as far as value is concerned, but with limited scope.
  • If you have a statement globally, such as int j = g() , then g() runs before main, so that j can be initialized.
  • You cannot have the same name for globals in 2 different C++ files unless one of them is static, which will make the global variable file-scoped.
  • Uninitialized built-in local variables get initialized to garbage, global ones to 0.
  • A static class variable in Java has just one copy across template flavors. Thus one cannot declare a static variable of the template type when defining the templated class. This, however is allowed in C++, since there is a copy per template flavor.
Well, this has definitely been an eye-opening experience for me. I hope I don't garbage-collect it all!

Sunday, March 25, 2012

#9 March 25

And so ends the 2nd part in the CS 371p trilogy...

This Friday we had the second test in the course and it was in the same format as the previous one - 100 marks worth of multiple choice questions and then 50 marks worth of coding problems. Since some students may still be taking make-up exams, I won't discuss the actual content of the test; however I will remark on its structure. The multiple choice questions were anything but "statistically independent" (I'm a machine learning sorta guy). Based on bits of C++ trivia, entire series of questions (ranging from 25-40 marks) had the same options hinging on the very same concept. In other words, if you had the misfortune of forgetting that concept, you were going to lose out big time! The test felt a lot like gambling in Vegas - when you hit it, you hit it big or you simply lost everything! Rather unfair....and it has also left me a bit averse to the letter "A".

This is also a good time to reflect on why I took the course and what I feel I'm getting out of it. When I registered for this course, I did it for 2 reasons - I had heard that Prof. Downing ran an excellent albeit tight class and I also wanted to hone my C++ skills. Looking objectively at the course so far - it has been run well, quizzes keeping you on your toes, projects that help you grow comfortable with good software development practices and a lot of information. But when I step back and look at the bigger picture - I feel like the course lacks substance. We're getting tons of information, no doubt about that, but a lot of it simply seems to be C++/ Java trivia that you would perhaps learn for a coding certification test. Honestly, the only "object-oriented" parts of the course - a couple of papers and the textbook, have been completely self-study. The one object-oriented project so far seemed to have more of an emphasis on formatting the output than anything else. I feel that the course could be so much more enriching if the contents of the textbook weren't simply dismissed by a 5 point quiz; rather actively discussed and debated in class. How about giving a software design scenario and then discussing how to engineer a good design using object-oriented programming. Talking about designing well-thought out interfaces to make more pluggable code. Discussing code reuse and inheritance hierarchies, discussing how to layer abstractions into your design. These are very important skills to learn and we would benefit a lot from the experience of Prof. Downing as well as the collective knowledge of the class. Yet week after week we end up poring over minutiae like "Java caches String literals" (and this is a senior level course) or the many little code snippets like "Filling out an array with values" or "Checking if 2 arrays are equal" that are simply not intellectually stimulating after you've gone through the first example and understood different iterators.

I know that a good programmer has all these tips and tricks under his belt. However, it would be so much better if these were an addendum to the course rather than its entirety. In fact, simply flipping what is assigned reading and what is actually covered in class would benefit students greatly in my opinion.

Sunday, March 18, 2012

#8 March 18

Welcome to the spring break edition of the 371p blog. I'm not entirely sure if we're even supposed to be writing one for this week, but hey I like tradition!

The only thing to discuss for this week is the Grades project. I had the impression that this could be easily done in a few hours. I was MISTAKEN! This has honestly been the most irritating project so far. The good first: implementation was a breeze and designing it by avoiding getters and setters was interesting and challenging.

But the sheer tedium of the formatted output! I think most of the time spent on this project was calculating what the width of a multitude of items would be and then how many corresponding spaces would make it look nice! Look, I'm all for formatted output - but please don't ask me to write unit tests where I have to manually count out spaces and -'s to the point where I'm going bat-crazy!

And that brings me to the next grouse - unit tests are good, but this "written-in-stone" 3 unit tests per function idea is not practical. There are some functions (like the constructors and destructors in the previous project) which don't need more than 1 or 2 unit tests. I often have way more than 3 unit tests for functions which have a number of corner cases etc., but I have started writing more monolithic functions (far less cohesive than I would want them to be) simply to avoid writing 3 unit tests for simple helper functions like calculating the number of digits in an integer etc. This is obviously not desirable and I hope Prof. Downing leaves it to the students' discretion as to what to unit test and to what degree.

I did learn a lot about C++ formatting - I'd become too used to the C-style printf format specifiers. The article on getters and setters was interesting too, though labeling them as evil is probably extreme. Anyway, I leave you with a meme I never knew existed:

Sunday, March 11, 2012

#7 Mar 11

Well this was a slow week in the OOP class. Most of this week was spent discussing the ins and outs of arrays in C++. How we can only use it as a pointer when passed as a functional argument, how you can dynamically initialize them with values, but cannot initialize them with the same syntactic sweetness as int i = j. The same thing goes for when you're trying to reassign an array tonanother array. Something as simple yet dumb as a = b where a and b are arrays can actually cause a memory leak if you have created a on the heap. So it all boils down to use vectors - they are a part of the standard template library, they provide the syntactic sugar which lets you handle them very nearly like built-in types and are also blazingly fast about it. But what personally tilts the balance in favor of vectors is the fact that they handle all memory management on their own under the covers, so the chances of having a memory leak are now very low as compared to when we were using arrays.

This also brings us to our first really Object Oriented project for the semester. We're basically given a bunch of scores for students in a course and are expected to compute the statistics on it. While honestly this doesn't really need an object oriented approach to solve it I can still see why making a Student object might be helpful - especially is this were to go on to become part of a more complex system. The getters and setters are evil ideology makes a lot of sense once you think about it, and also brings up the question - how do you come up with a good design. In my case, I'm keeping most of the statistical functionality with the Course class and only personal stuff like ID and individual scores with the Student. Of course, this means that student objects will have to pass over their vector of scores to the course object, but I could not see a way around this minimal message passing. This project also made me realize how much I like Python :)

Sunday, March 4, 2012

#6 March 4

Another week and some more intricacies of C++ come to light - the many different uses of the const keyword. While I have covered const pointers before, it's still handy to brush up on how const can change the usage of a variable or a pointer depending on how you place it in the declaration.

So let's break things down:
When you declare something as const, quite intuitively, you're saying that it can't be changed. This obviously means that a const variable MUST be initialized during declaration.
So, for example:

const i = 2;

would initialize the constant in i to 2 and then you would not be able to modify it (i becomes read-only).

This becomes slightly more tricky once you start using pointers:

const int* p = &i;
int* const p = &i;

In the first case, we're declaring a pointer to a constant, i.e., the value being pointed to by p (in this case i) must be constant and cannot be changed, while p itself can. Thus I can reassign p, but something like ++*p would not be allowed.

In the second case, we're declaring a constant pointer. This means once initialized to some address, we will not be able to modify p. This is particularly useful if you think of pointers being returned to indicate the start of an allocated memory location - we want to ensure that we keep this address constant.

There are other variants to this, including mixing it up with references, but once these 2 have been clearly distinguished, the rest fall into place.