Monday, 27 January 2014

Object Orientated Programming (OOP)

Hello fellow students, TA's and  instructors. From this blog, you will be able to monitor my progress throughout this course- - from my trials and tribulations, to my accomplishments and all those pesky syntax errors in between. Each week (maybe more depending on time constraints), I will be updating this blog, with a recap of the material I have learnt in CSC148, along with my own personal reflection on the material. Hopefully, throughout this process I will gain valuable insight into my own problem solving strategies, and come out of this course a stronger, more inventive, and more independent programmer.

To start off my blog, I will be talking about my assigned topic for week 3 of this course, "Object Orientating Programming", or OOP for short. Having already been introduced to this programming technique in CSC108 briefly, I have had some experiences with it, but in that course, the depth of the material was quite light, and we mainly covered it as a small precursor, for those who intended to take 148 in the winter. As a result, when I was introduced to this concept for a second time, at the start of 148, the content was far more rigorous and challenging then I had been expecting. As a brief recap, OOP is, as the name suggests, a style of programming which revolves around programming for specific objects. At first, I wondered why is this type of programming so helpful? What's the point of creating specific date types and methods and classes, to program for specific objects? This idea frustrated me at first, until I did some background reading and realized how essential this type of programming could be. It wasn't until, I slowly worked through the examples in class and came up with the analogy below, that I truly understand the powerful nature of OOP.

As an analogy to show how I understand OOP works, let us say we have an object like a hockey stick, a hockey player would use for a hockey game. Obviously the hockey stick would have to be unique in some fashion and it would have to have certain characteristics, that make it some individual persons unique stick. These characteristics (or attributes), could include; the model of the stick, colour, weight and length just to name a few. Now lets say, we wanted to code a program that would have certain functions, that when we take the characteristics above, give us certain results. For instance, if we used that particular stick and we defined a certain function to swing the stick in a parabolic arc, we would get a specific trajectory. This can all be done, using the conventional style of programming, where we have a "procedural design". However, issues soon arise with this style of programming, if we wanted to change the hockey stick in some ways, and change its attributes. What if the stick becomes more and more worn out, every time we shoot it, what if the colour of the stick slowly fades, what if the weight of the stick increases when we play due to ice buildup on the hockey rink? Does this mean every time we wanted a new stick, with these specific characteristics, each time we wanted a new stick, we would have to create a completely new stick - all the way from scratch. Furthermore, since we have functions based around the original hockey sticks attributes, Python wouldn't allow us to change the stick, and have the functions to adapt to these changes as they go. It would be far more simply, to start off with creating and coding  a basic hockey stick, and then to add code to it along the way, when we needed to change it around and let the functions change with it- exactly what OOP allows us to do.

Another important aspect of classes that was discussed, was the concept of "inheritance", and how two classes can inherit properties from one another. For instance if we had two classes, you may be wondering-how can we get stuff from one class to another? How can our methods, which sometimes may be helpful in more than one method, to be transferred to another one. This concept, actual struck me as something that may be strangle intuitive with the language, since a coding technique like this would allow me to seamlessly mix my classes into one with its functions. The way I personally picture inheritance to work, is if I have a "parent" and a "child", then the child obviously inherits some "things" from its parents-the same way with with parent classes. In python coding, you would write this as class child(parent), where the child "inherits" certain things from the class parent. This is also important I realized, since when you do this you can specify certain things in a child class, that you only have to write generally in a parent class. However, when it came to the manner in which inheritance operates, I was completely unsure as to how it worked. Essentially I realized it boils down to three main uses: alteration, implying, overriding. The first use, to imply a function in the parent class but not in the child block allows for you to inherit everything from the previous parent class-with only a pass statement needed. The second use, over riding, is a very special and I realized, helpful case to consider when using inheritance. What if you want to inherit something sometimes, but not all the time? In this case, you would have to override the code in the parent class. This is done through simply defining the same function in the parent class, as you had in the childs class, and letting python understand that the changes in the function, are for it to "over ride" what was used in the parents class. The very last use of inheritance is with altering a code before or after a parent class runs. Do to this, you simply use the example of overriding previously talked about and then use this new functions called super(), to then call the original version of the parent class. This concept, initially confused me, as it seemed initially strange to go back and forth between altered and changed versions of classes, but I realized that super(), did help to clear up this confusion, as python makes these changes for you itself, and all you are required to do as the programmer is specify which class (at which instance of time), you need to use when calling a specific function. Another alternative to inheritance, is to use composition- a technique by which we use classes and other modules, rather than using inheritance to relate classes together.

My personal take on OOP, and my analysis on the material this week is brief, but I feel its important as it gives my own take on the material. OOP seems to be quite the helpful tool in computer programming, with its unique benefits, especially when it comes to code that is repeated quite often, the the objects are always changing-yet you want to apply the same functions to them. Secondly, when it comes to the idea of inheritance, this technique seems like an ideal fashion for creating "hierarchies" of sorts within the classes, and ensuring that each class is built upon another. The problem with this is over time, with the super() function, it will become confusing to understand where in the hierarchy you actually are, so it may be far more simply to use composition, and define the classes as I go.

Some problems that I faced this week regarding learning about OOP in python, include struggles as basic as grasping the concept surrounding OOP, to coding the exercise, given in the second week of the course. In terms of the concepts surrounding OOP, my analogy, and working through the codes in class really helped me to understand the material in far greater depth. In particular, the syntax surrounding classes, with self.() and these other new coding techniques were only learn over time. Secondly, over time I became more fluid with my coding of classes, understanding what the class was referring to, how to initialize them, and how to use inheritance to relate them together. When it came time to complete my exercise for part B, I tore through it quickly-I initially only had difficulty understand when is it appropriate to use the self.() notation, and how to create the instance variables at the smart. Once I did, and realized that the self.() notation, is only used when referring to the class object itself, and that instance variables are stored at the start, when we initialize a class-OOP became a breeze for me.

That's all for now!