Sunday, 22 February 2015

Object-oriented Programming (OOP)

In object-oriented programming, creating objects containing both data and functionality is the focus. The definition of OOP is that it is a model for writing computer programs, modeled around the interactions between objects. It involves writing classes that generate objects and define their structure. Object-oriented programming involves working with ADTs, or abstract data types.

For example, you can define a class Point, and give it the attributes x and y, as mentioned previously. Now that the class is defined, objects of this type Point can be created. When this class was created, a type of this class was also created. Point objects can also be called instances of type Point

class Point:
    """
    """
    def __init__(self, x, y):
        """ (Point, int, int) -> NoneType

        """
        self.x = x
        self.y = y

Objects of this instance can be generated like this:

>>> p = Point(3, 4)
>>> p.x   # p.x and p.y just accesses the values for this instance 
3
>>> p.y
4

You can even write methods in classes, which look like functions but are a part of objects. As mentioned before, a method for this class could be distance_from_origin. It can be called like this on an object:

>>> p.distance_from_origin()

This way, the object p has data in the form of x and y, and functionality in the form of the method, distance_from_origin. Another excellent, existing example of object-creating ADTs are stacks. Stack is a class and type, which has data and also functions in terms of push(), pop() and is_empty(). In conclusion, object-oriented programming involves creating objects through classes, with data in the form of attributes and functions in the form of methods.

Monday, 16 February 2015

Tracing recursion in Week 4

For me, tracing recursion is not really a difficult concept, as it involves going into a list and just using a function on the various elements in the list. It basically involves a function calling itself, as mentioned previously. An example of recursion on a list can be:
L = [[1, 5], [9, 8], [1, 2, 3, 4]]
sum([sum_list(x) for x in L]) - this takes the sum of elements at each index position in L, or just x if x is an integer

To trace this, just do:

>>> sum_list[[1, 5], [9, 8], [1, 2, 3, 4]]
>>> sum([sum_list[1, 5], sum_list[9, 8], sum_list[1, 2, 3, 4]])
>>> sum([6, 17, 10])
33

Tracing inside lists more complicated than this one can be confusing, but if one just traces simpler examples first, he/she can automatically write the result of the nested list in upcoming examples of lists of increasing complexity. They will not need to trace through individual elements in the nested lists again, such as [sum_list(9), sum_list(8)]. In fact, when one moves on to tracing more and more complicated list calls, they must not do this. This is because they would have already traced through like this in previous simpler examples.

The depth of the list is also not that difficult to understand. It took me some time, however, to understand how the code for determining the maximum depth of a list made sense and worked. This is the code for determining the depth for the list:

if instance(L, list):
     return 1 + max([depth(x) for x in L])
else:   # L is not a list
     return 0

At first, I was confused as to how this function was able to determine the depth of a nested list with just the word depth(x) in its code. Before finding out the solution, I thought about it to myself and got the correct answer just by seeing the number of lists and nested lists. A simple example of this is:

>>> depth(17)
0
>>> depth([1, 2, 3])
1                   # because there is only one list
>>> depth([3, 4, [2, 5], 9])
2                   # because there is a list and nested list

Later, I figured out how the code worked, just by remembering that it was nothing but recursion at action! Since it called itself, depth(x) works on a nested list, such as [2, 5], just like it would work on a list without a nested list, such as [1, 2, 3]. 

Furthermore, the professor also covered how to find the maximum number in a simple list, lists that are one deep, two deep and etc. For example, this is a call to a simple/flat list:

>>> rec_max([2, 5, 1, 3])
>>> max([rec_max(2), rec_max(5), rec_max(1), rec_max(3)])
>>> max(2, 5, 1, 3)
5

When the list increases in complexity, it must be evaluated in the same way as the sum_list() and depth() functions. One thing that I found particularly fascinating was recursion in a file named tree_burst.py. This gave a visual application of recursion and I found this particularly interesting, as it involved red, blue and green arrows branching out in 3 different directions. These arrows formed a ternary tree. I didn't fully understand how this implementation of recursion worked, but I enjoyed it as I like learning through visuals.

By far, this course continues to become more and more interesting, and challenging as well. I look forward to upcoming material and am a bit apprehensive of their level of difficulty.

Friday, 6 February 2015

My first four weeks in CSC148

In my first four weeks in this course, I have learnt quite a lot, especially about classes and recursion. To me, the concepts are not too difficult, but they are not too simple either. The first thing that I learnt is to look for a few key things in a class description to design a class. I found this particularly useful. These things are: an important noun (for the class name), attributes, and necessary operations. For example, for a class Point, its attributes are the x and y coordinates, and its necessary operations can be calculating the distance between a point and the origin, distance between two points and the midpoint between the two points. I also learnt how to implement an __eq__, __str__ and __repr__ method. Interestingly, the concept of controlling access to attributes and classes was also taught. Because of this, I now know that _attribute represent an attribute that can be controlled by the creator. Additionally, I also learnt how a stack is designed, and the three main functions associated with this class, push()pop() and is_empty().

As well, the professor covered how to extend a class's (superclass) characteristics in a subclass. Also, for methods in a superclass that are supposed to be in a subclass, all one has to do is raise an exception (ex. raise Exception("This cannot be done.")). One can raise existing Exceptions, or make up his or her own Exceptions. Furthermore, I learnt how to trace through a list to add items up in a process known as recursion. Recursion is a very interesting and unique concept as it involves a function calling itself. One can use this method to trace lists of varying depths, like this:

sum_list[1, 2, 3, 4, 5, 6] or sum_list [1, [2, 3], 4, 5, 6] or even sum_list[1, 2, [3, 4, [5, 6], 7], 8]

We were given weekly lab exercises based on what we were taught, and quizzes in our tutorials. I found the quizzes quite tough, actually. I was confused about how to answer the questions, so I didn't end up doing well on them. The concepts are easy to understand, but applying them requires a lot of thinking and can be difficult for me. This is why I plan to ask for help from various people, including TA's at the help centre. Despite the challenges, this course has been interesting so far, and I am looking forward to learning more about advanced programming.