CC 03 Objects
CC 03 Objects
Patterns
A Historical
Perspective
Dr. Charles R. Severance
www.cc4e.com
code.cc4e.com (sample code)
online.dr-chuck.com
Outline – Object Oriented
• Review from previous courses
• A historical perspective
• Using C to build an OO support
• Building a Python str() class in C
• Building a Python list() class in C
• Building a Python dict() class in C
• Reference: 6.5.1
OO Review – online.dr-chuck.com
• OO Python
• Python for Everybody – Chapter 14
• Django for Everybody
• OO JavaScript
• Django for Everybody
• Web Applications for Everybody
class Point:
constructor def __init__(self, x, y):
self.x = x attributes
attributes self.y = y
def dump(self):
methods print('Object point@%x x=%f y=%f' % (id(self),self.x,self.y))
def origin(self):
return math.sqrt(self.x*self.x+self.y*self.y)
pt = Point(4.0, 5.0)
Point.dump(pt) constructed
print('Origin',pt.origin())
del(pt)
destructed
kr_03_01.py
Object Orientation
Across Time and Programming Languages
Science Calculations
System
System
C uses curly
braces { } for
code blocks.
Scripting/
Interpreted
p://en.wikipedia.org/wiki/History_of_programming_languages
Procedural
Hybrid
Object Oriented
Classes were
added to PHP in
ps://en.wikipedia.org/wiki/Object-oriented_programming 2000
OO Implementations Over Time
• Python (1991)
• C++ (1980)
• Java (1995)
• JavaScript (1995)
• PHP (2000)
• C# (2001)
P.S. The more languages you know the better – Dr. Chuck
import math
Object point@102ad1f10 x=4.000000 y=5.000000
class Point: Origin 6.4031242374328485
def __init__(self, x, y):
self.x = x
self.y = y
Python uses the concept of "self" to refer to
def dump(self): the variables stored in the current instance.
print('Object point@%x x=%f y=%f' % The constructor is by convention "__init__".
(id(self),self.x,self.y))
def origin(self):
return math.sqrt(self.x*self.x+self.y*self.y)
pt = Point(4.0, 5.0)
Point.dump(pt)
print('Origin',pt.origin())
del(pt)
1991 cc_03_01.py
#include <iostream>
#include <math.h>
class Point {
public:
double x, y; Object point x=4.000000 y=5.000000
Origin: 6.40312
Point(double xc, double yc) {
x = xc;
y = yc; C++ was initially implemented as a pre-
};
processing pass that did textual
void dump() { transformations and then passed the code
printf("Object point x=%f y=%f\n", x, y); into the C compiler. There is no concept of
} "self" or "this".
double origin() {
return sqrt(x*x+y*y);
}
};
int main() {
Point pt(4.0, 5.0);
pt.dump();
printf("Origin: %f\n", pt.origin());
}
1980 cc_03_01.cpp
import java.lang.Math;
pt.dump();
console.log("Origin %f",pt.origin());
1995 cc_03_01.js
class Point { Object point x=4.000000 y=5.000000
private $x, $y; Origin 6.403124
class TestPoint{
public static void Main(string[] args)
{
Point pt = new Point(4.0, 5.0);
pt.dump();
Console.WriteLine("Origin {0}", pt.origin());
}
} 2001 cc_03_01.cs
Using C to Build OO
Support
How was Python's OO layered on top of C?
import math
Object point@102ad1f10 x=4.000000 y=5.000000
class Point: Origin 6.4031242374328485
def __init__(self, x, y):
self.x = x
self.y = y
def dump(self):
print('Object point@%x x=%f y=%f' %
(id(self),self.x,self.y))
def origin(self):
return math.sqrt(self.x*self.x+self.y*self.y)
pt = Point(4.0, 5.0)
Point.dump(pt)
print('Origin',pt.origin())
del(pt)
1991 cc_03_01.py
#include <stdio.h> struct Point * point_new(double x, double y) {
#include <stdlib.h> struct Point *p = malloc(sizeof(*p));
#include <math.h> p->x = x;
p->y = y;
struct Point { p->dump = &point_dump;
double x; p->origin = &point_origin;
double y; p->del = &point_del;
return p;
void (*del)(const struct Point* self); }
void (*dump)(const struct Point* self);
double (*origin)(const struct Point* self); int main(void)
}; {
struct Point * pt = point_new(4.0,5.0);
void point_dump(const struct Point* self) pt->dump(pt);
{ printf("Origin %f\n", pt->origin(pt));
printf("Object point@%p x=%f y=%f\n", pt->del(pt);
self, self->x, self->y); }
}
1975 cc_03_01.c
Building a Python str()
Class
int main(void)
{
printf("Testing pystr class\n");
struct pystr * x = pystr_new();
pystr_dump(x);
x = str()
x = x + 'H' pystr_append(x, 'H');
print(x) pystr_dump(x);
x = x + 'ello world'
print(x) pystr_appends(x, "ello world");
x = 'A completely new string' pystr_dump(x);
print("String = ", x)
print("Length = ", len(x)) pystr_assign(x, "A completely new string");
printf("String = %s\n", pystr_str(x));
printf("Length = %d\n", pystr_len(x));
pystr_del(x);
}
H
Hello world
String = A completely new string Testing pystr class
Length = 23 Object length=0 alloc=10 data=
Object length=1 alloc=10 data=H
Object length=11 alloc=20 data=Hello world
String = A completely new string
Length = 23
cc_03_02.py
struct pystr
String Structure
{
int length;
int alloc; /* The length of *data */
and Constructor
char *data;
};
/* x = str() */
struct pystr * pystr_new() {
struct pystr *p = malloc(sizeof(*p));
p->length = 0;
p->alloc = 10;
p->data = malloc(10);
p->data[0] = '\0'; length: 0
return p;
}
alloc: 10
data: ∅ ? ? ? ? ? ? ? ? ?
...
int main(void)
{
struct pystr * x = pystr_new();
...
}
cc_03_02.c
struct pystr
{
int length;
char *data;
int alloc; /* The length of *data */
Some Methods
};
/* Constructor – x = str() */
struct pystr * pystr_new() { int pystr_len(const struct pystr* self)
struct pystr *p = malloc(sizeof(*p)); {
p->length = 0; return self->length;
p->alloc = 10; }
p->data = malloc(10);
p->data[0] = '\0'; char *pystr_str(const struct pystr* self)
return p; {
} return self->data;
}
/* Destructor – del(x) */
void pystr_del(const struct pystr* self) {
free((void *)self->data); /* free string first */
free((void *)self);
}
/* x = x + "hello"; */
• We have three methods to
put data into our structure void pystr_appends(struct pystr* self, char *str) {
/* Need one line of code here */
}
• You can build pystr_append()
/* x = "hello"; */
and then use it to make the
code in pystr_appends() and void pystr_assign(struct pystr* self, char *str) {
/* Need three lines of code here */
pystr_assign() very simple. }
int main() {
• Objects like to reuse their struct pystr * x = pystr_new();
pystr_append()
int length;
char *data;
int alloc; /* the length of *data */
};
cc_03_02.c
pystr_append() length: 0
alloc: 10
data: ∅ ? ? ? ? ? ? ? ? ?
struct pystr
{
int length;
char *data;
int alloc; /* the length of *data */ length: 1
};
alloc: 10
int main() {
struct pystr * x = pystr_new(); data: H ∅ ? ? ? ? ? ? ? ?
pystr_append(x, 'H');
pystr_append(x, 'e');
}
length: 2
alloc: 10
data: H e ∅ ? ? ? ? ? ? ?
cc_03_02.c
length: 2 pystr_append()
alloc: 10
data: H e ∅ ? ? ? ? ? ? ? int main() {
struct pystr * x = pystr_new();
pystr_append(x, 'H');
pystr_append(x, 'e');
pystr_append(x, 'l');
pystr_append(x, 'l');
length: 9 pystr_append(x, 'o');
pystr_append(x, ' ');
alloc: 10 pystr_append(x, 'w');
pystr_append(x, 'o');
data: H e l l o w o r ∅ pystr_append(x, 'r');
pystr_append(x, 'l');
pystr_append(x, 'd');
length: 11 realloc() }
alloc: 20
data: H e l l o w o r l d ∅ ? ? ? ? ? ? ? ?
realloc() struct pystr * pystr_new() {
struct pystr *p = malloc(sizeof(*p));
p->length = 0;
p->alloc = 10;
• We can extend the size of a p->data = malloc(10);
p->data[0] = '\0';
dynamically allocated area by return p;
current pointer to the area void pystr_append(struct pystr* self, char ch) {
/* If we don't have space for 1 character plus
and the needed size termination, allocate 10 more */
https://www.w3schools.in/c-programming/dynamic-memory-allocation#realloc-function
int main(void)
{
pystr_append(x, 'H');
pystr_dump(x);
cc_03_02.c
cc_03_02.py
Building a Python list()
Class
lst = list(); int main(void)
lst.append("Hello world"); {
print(lst) struct pylist * lst = pylist_new();
lst.append("Catch phrase"); pylist_append(lst, "Hello world");
print(lst) pylist_print(lst);
lst.append("Brian"); pylist_append(lst, "Catch phrase");
print(lst) pylist_print(lst);
print("Length =", len(lst)); pylist_append(lst, "Brian");
pylist_print(lst);
print("Brian?", lst.index("Brian")); printf("Length = %d\n", pylist_len(lst));
printf("Brian? %d\n", pylist_index(lst, "Brian"));
if "Bob" in lst: printf("Bob? %d\n", pylist_index(lst, "Bob"));
print("Bob?", lst.index("Bob")); pylist_del(lst);
else: }
print("Bob? 404");
cc_03_03.c
cc_03_03.py
Basic stuff /* Destructor - del(lst) */
void pylist_del(struct pylist* self) {
struct lnode *cur, *next;
cur = self->head;
while(cur) {
struct lnode {
free(cur->text);
char *text;
next = cur->next;
struct lnode *next;
free(cur);
};
cur = next;
}
struct pylist {
free((void *)self);
struct lnode *head;
}
struct lnode *tail;
int count;
};
cc_03_03.c
Freeing Dynamic Memory 1
/* Destructor - del(lst) */ text: C
void pylist_del(struct pylist* self) { 2
struct lnode *cur, *next; next:
cur = self->head;
while(cur) { 4 3
free(cur->text); 1, 3, 5
text: is
next = cur->next;
free(cur); 2, 4, 6 next:
cur = next;
7
}
head: 6 5
free((void *)self); 7
} tail: text: Fun
count: 3 next: ∅
cc_03_03.c
Printing a list
/* print(lst) */
void pylist_print(struct pylist* self)
{
['Hello world']
/* About 10 lines of code ['Hello world', 'Catch phrase']
The output should match Python's ['Hello world', 'Catch phrase', 'Brian']
list output Length = 3
Brian? 2
['Hello world', 'Catch phrase'] Bob? -1
Remember that unlike Python's print() which always includes a newline, C's printf() only
adds a newline (\n) if you include it in the format string. So it is easy to print "long lines"
with no line breaks with for loops in C.
cc_03_03.c
More methods for you to
build
/* len(lst) */
int pylist_len(const struct pylist* self)
{
/* One line of code */
}
/* lst.append("Hello world") */
void pylist_append(struct pylist* self, char *str) {
/* Review: Chapter 6 lectures and assignments */
}
cc_03_03.c
Using our class int main(void)
{
struct pylist * lst = pylist_new();
pylist_append(lst, "Hello world");
pylist_print(lst);
• This is almost line for line pylist_append(lst, "Catch phrase");
much identical }
pylist_del(lst);
['Hello world']
['Hello world', 'Catch phrase']
['Hello world', 'Catch phrase', 'Brian']
Length = 3
Brian? 2
Bob? -1
cc_03_03.c
cc_03_03.py
Building a Python dict()
Class
Python Dictionary
{'z': 'Catch phrase'}
dct = dict(); {'z': 'W'}
dct["z"] = "Catch phrase" {'z': 'W', 'y': 'B', 'c': 'C', 'a': 'D'}
print(dct); Length = 4
dct["z"] = "W" z= W
print(dct); x= 404
dct["y"] = "B"
dct["c"] = "C" Dump
dct["a"] = "D" z=W
print(dct); y=B
print("Length =", len(dct)); c=C
print("z=", dct.get("z", 404)) a=D
print("x=", dct.get("x", 404))
print("\nDump")
for key in dct:
print(key+"="+dct[key])
cc_03_04.py
C Dictionary
int main(void)
{
struct pydict * dct = pydict_new(); {'z': 'Catch phrase'}
pydict_put(dct, "z", "Catch phrase"); {'z': 'W'}
pydict_print(dct); {'z': 'W', 'y': 'B', 'c': 'C', 'a': 'D'}
pydict_put(dct, "z", "W"); Length =4
pydict_print(dct); z=W
pydict_put(dct, "y", "B"); x=(null)
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D"); Dump
pydict_print(dct); z=W
printf("Length =%d\n",pydict_len(dct)); y=B
c=C
printf("z=%s\n", pydict_get(dct, "z")); a=D
printf("x=%s\n", pydict_get(dct, "x"));
printf("\nDump\n");
for(struct dnode * cur = dct->head; cur != NULL ; cur = cur->next ) {
printf("%s=%s\n", cur->key, cur->value);
}
pydict_del(dct);
} cc_03_04.c
/* Destructor - del(dct) */
/* print(lst) */
/* {'z': 'W', 'y': 'B', 'c': 'C', 'a': 'D'} */
void pydict_print(struct pydict* self)
{
/* Some code */
}
cc_03_04.c
A Reusable Method
struct dnode* pydict_find(struct pydict* self, char *key)
{
/* Six lines of code */
}
int main(void)
{
struct pydict * dct = pydict_new();
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W");
pydict_put(dct, "y", "B");
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D");
...
}
cc_03_04.c
head:
struct dnode {
tail:
char *key;
char *value; z
struct dnode *next; key:
};
value:
struct pydict { Catch phrase
struct dnode *head;
struct dnode *tail;
∅
int count;
};
int main(void)
{
struct pydict * dct = pydict_new();
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W");
pydict_put(dct, "y", "B");
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D");
...
}
cc_03_04.c
head:
struct dnode {
tail:
char *key;
char *value; z
struct dnode *next; key:
};
value:
struct pydict { W
struct dnode *head;
struct dnode *tail;
∅
int count;
}; Free Space:
int main(void) Catch phrase
{
struct pydict * dct = pydict_new();
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W");
pydict_put(dct, "y", "B");
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D"); Make sure to free the data in value that was the
... "Catch phrase" string before allocating the "W"
}
string and setting value to point to the newly
allocated string.
head:
struct dnode {
tail:
char *key;
char *value; z
struct dnode *next; key:
};
value:
struct pydict { W
struct dnode *head;
struct dnode *tail; y
key:
int count;
}; value:
B
int main(void)
{
struct pydict * dct = pydict_new(); ∅
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W");
pydict_put(dct, "y", "B");
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D");
...
}
cc_03_04.c
head:
struct dnode {
tail:
char *key;
char *value; z
struct dnode *next; key:
};
value:
struct pydict { W
struct dnode *head;
struct dnode *tail; y
key:
int count;
}; value:
B
int main(void)
{ c
struct pydict * dct = pydict_new(); key:
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W"); value:
pydict_put(dct, "y", "B"); C
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D");
...
∅
}
cc_03_04.c
head:
struct dnode {
tail:
char *key;
char *value; z
struct dnode *next; key:
};
value:
struct pydict { W
struct dnode *head;
struct dnode *tail; y
key:
int count;
}; value:
B
int main(void)
{ c
struct pydict * dct = pydict_new(); key:
pydict_put(dct, "z", "Catch phrase");
pydict_put(dct, "z", "W"); value:
pydict_put(dct, "y", "B"); C
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D"); a
...
key:
} value:
D
cc_03_04.c
∅
Python OrderedDict() versus dict()
• Before Python 3.7 the dict() class did not remember the order of
items as they were inserted
• The Pre-3.7 Python used internal implementation used hashing to give fast
performance for key lookup and insert
• Since we have implemented dictionary functionality on top of a linked
list, our code behaves more like an OrderedDict()
• Our insert is quick but our key lookup using get() is slow as it might
need to scan the entire list
• We will address this performance issue in an upcoming lecture with
an awesome data structure that combines linked lists and hashing
Summary
• OO Review from previous courses
• OO – A historical perspective
• Using C to build an OO support
• Building a Python str() class in C
• Building a Python list() class in C
• Building a Python dict() class in C (OrderedDict actually)
Acknowledgements / Contributions
These slides are Copyright 2023- Charles R. Severance (online.dr-chuck.com) Continue new Contributors and Translators here
as part of www.cc4e.com and made available under a Creative Commons
Attribution 4.0 License. Please maintain this last slide in all copies of the
document to comply with the attribution requirements of the license. If you
make a change, feel free to add your name and organization to the list of
contributors on this page as you republish the materials.
Insert new Contributors and Translators here including names and dates