├── code ├── rc3build │ ├── t.cpp │ ├── .gitignore │ ├── even.cpp │ ├── odd.cpp │ ├── sum.cpp │ ├── prod.cpp │ ├── sum_large.c │ ├── main.cpp │ └── Makefile ├── rc2xm │ ├── rc2xm │ ├── xm.in │ ├── run │ │ ├── rc2xm │ │ ├── xm3.in │ │ ├── xm.in │ │ ├── xm2.in │ │ └── out │ └── xm.cpp ├── rc3init │ ├── a.cpp │ ├── init_arr.cpp │ └── init_str.cpp ├── rc8class │ ├── integer.cpp │ ├── dec.cpp │ ├── inc.cpp │ ├── integer.h │ └── main.cpp ├── rc5unroll │ ├── out │ ├── a.cpp │ └── file.h ├── rc8init │ ├── .vscode │ │ └── settings.json │ ├── intset_ctor.h │ ├── oddintset.cpp │ ├── fastintset.cpp │ ├── fastintset.h │ ├── oddintset.h │ └── intset.cpp ├── rc10synthesize │ ├── base.h │ ├── ok.cpp │ └── error.cpp ├── rc5pz2 │ └── a.cpp ├── rc5pz1 │ ├── a.cpp │ └── b.cpp.save ├── Linked-List │ ├── .vscode │ │ └── settings.json │ ├── IntList.h │ ├── Makefile │ ├── main.cpp │ └── IntList.cpp ├── rc10virtual │ ├── vtable_qux.cpp │ ├── call.cpp │ └── class.h ├── rc10access │ ├── protected.h │ ├── private.h │ └── public.h ├── rc5pz3 │ └── a.cpp ├── rc3arr │ ├── arr.cpp │ └── run.sh ├── rc8intset │ ├── intset.h │ ├── intset_ctor.h │ └── intset.cpp ├── rc9dtor1 │ ├── ex3.cpp │ ├── driver.cpp │ ├── ex2.cpp │ ├── classes.h │ ├── ex3.h │ └── ex2.h ├── rc5pz25 │ └── a.cpp ├── rc9raii │ ├── ex.cpp │ └── ex.h ├── rc9cpctor │ └── ex1.cpp ├── rc11cp │ └── poly.cpp ├── rc7writetree │ └── writetree.cpp ├── rc10compatible │ ├── class.h │ ├── copy.cpp │ └── class.cpp ├── rc8const │ ├── class.h │ └── main.cpp ├── rc4fptr │ └── fptr.cpp ├── rc8this │ └── main.cpp ├── rc9sgt │ └── sgt.h ├── rc5qsort │ └── nonrec.cpp └── IntSet-Default-Argument │ ├── Makefile │ ├── main.cpp │ ├── IntSet.cpp │ └── IntSet.h ├── main.pdf ├── fig ├── s1.PNG ├── s2.PNG ├── rc11dry.PNG ├── rc11p4.PNG ├── rc11pc1.PNG ├── rc11pc2.PNG ├── rc11pc3.PNG ├── rc8fig.pptx ├── rc5_const.PNG ├── rc5_vg101.PNG ├── rc6gtest.png ├── rc6stdexp.png ├── rc8link1.png ├── rc8link2.png ├── low-coupling.jpg ├── rc2_linuxfs.png ├── rc3_tostring.PNG ├── barbara-liskov.jpg ├── design_patterns.jpg ├── high-coupling.jpg └── low-coupling-flex.jpg ├── Makefile ├── macro.sty ├── README.md ├── main.tex ├── .gitignore ├── week12.tex ├── week11.tex ├── week8.tex ├── week6.tex ├── week5.tex ├── week2.tex └── week4.tex /code/rc3build/t.cpp: -------------------------------------------------------------------------------- 1 | int main[-1u] = {1}; 2 | -------------------------------------------------------------------------------- /code/rc3build/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore some temp files 2 | main 3 | run -------------------------------------------------------------------------------- /main.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/main.pdf -------------------------------------------------------------------------------- /fig/s1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/s1.PNG -------------------------------------------------------------------------------- /fig/s2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/s2.PNG -------------------------------------------------------------------------------- /fig/rc11dry.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc11dry.PNG -------------------------------------------------------------------------------- /fig/rc11p4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc11p4.PNG -------------------------------------------------------------------------------- /fig/rc11pc1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc11pc1.PNG -------------------------------------------------------------------------------- /fig/rc11pc2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc11pc2.PNG -------------------------------------------------------------------------------- /fig/rc11pc3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc11pc3.PNG -------------------------------------------------------------------------------- /fig/rc8fig.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc8fig.pptx -------------------------------------------------------------------------------- /code/rc2xm/rc2xm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/code/rc2xm/rc2xm -------------------------------------------------------------------------------- /code/rc2xm/xm.in: -------------------------------------------------------------------------------- 1 | xd 2 | cg 3 | hss 4 | xtt 5 | qs 6 | jcc 7 | xdtql 8 | zdnxd 9 | -------------------------------------------------------------------------------- /fig/rc5_const.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc5_const.PNG -------------------------------------------------------------------------------- /fig/rc5_vg101.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc5_vg101.PNG -------------------------------------------------------------------------------- /fig/rc6gtest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc6gtest.png -------------------------------------------------------------------------------- /fig/rc6stdexp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc6stdexp.png -------------------------------------------------------------------------------- /fig/rc8link1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc8link1.png -------------------------------------------------------------------------------- /fig/rc8link2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc8link2.png -------------------------------------------------------------------------------- /code/rc2xm/run/rc2xm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/code/rc2xm/run/rc2xm -------------------------------------------------------------------------------- /code/rc2xm/run/xm3.in: -------------------------------------------------------------------------------- 1 | xd 2 | cg 3 | hss 4 | xtt 5 | qs 6 | jcc 7 | xdtql 8 | zdnxd 9 | -------------------------------------------------------------------------------- /fig/low-coupling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/low-coupling.jpg -------------------------------------------------------------------------------- /fig/rc2_linuxfs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc2_linuxfs.png -------------------------------------------------------------------------------- /fig/rc3_tostring.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/rc3_tostring.PNG -------------------------------------------------------------------------------- /code/rc3init/a.cpp: -------------------------------------------------------------------------------- 1 | void f(int x[]) { 2 | x++; 3 | } 4 | 5 | int main() { 6 | f(new int); 7 | } 8 | -------------------------------------------------------------------------------- /fig/barbara-liskov.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/barbara-liskov.jpg -------------------------------------------------------------------------------- /fig/design_patterns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/design_patterns.jpg -------------------------------------------------------------------------------- /fig/high-coupling.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/high-coupling.jpg -------------------------------------------------------------------------------- /code/rc3build/even.cpp: -------------------------------------------------------------------------------- 1 | int number[] = {2, 4, 6, 8, 10}; 2 | int size = sizeof(number) / sizeof(*number); -------------------------------------------------------------------------------- /code/rc3build/odd.cpp: -------------------------------------------------------------------------------- 1 | int number[] = {1, 3, 5, 7, 9}; 2 | int size = sizeof(number) / sizeof(*number); 3 | -------------------------------------------------------------------------------- /code/rc8class/integer.cpp: -------------------------------------------------------------------------------- 1 | #include "integer.h" 2 | void Integer::set(int v) { 3 | value = v; 4 | } -------------------------------------------------------------------------------- /fig/low-coupling-flex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tripack45/VE280-Notes/HEAD/fig/low-coupling-flex.jpg -------------------------------------------------------------------------------- /code/rc5unroll/out: -------------------------------------------------------------------------------- 1 | Opended : file1.in // Opended : file2.in 2 | I Returned! // Closed file2.in // Closed file1.in 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pdflatex -output-directory=build -shell-escape -- main.tex 3 | 4 | clean: 5 | rm -rf ./build/* 6 | 7 | -------------------------------------------------------------------------------- /code/rc8class/dec.cpp: -------------------------------------------------------------------------------- 1 | #include "integer.h" 2 | void dec(Integer& i) { 3 | int old = i.get(); 4 | i.set(old - 1); 5 | } -------------------------------------------------------------------------------- /code/rc8class/inc.cpp: -------------------------------------------------------------------------------- 1 | #include "integer.h" 2 | void inc(Integer& i) { 3 | int old = i.get(); 4 | i.set(old + 1); 5 | } -------------------------------------------------------------------------------- /code/rc3build/sum.cpp: -------------------------------------------------------------------------------- 1 | int reduce(int number[], int size) { 2 | int sum = 0; 3 | while (--size) sum += number[size]; 4 | return sum; 5 | } -------------------------------------------------------------------------------- /code/rc3build/prod.cpp: -------------------------------------------------------------------------------- 1 | int reduce(int number[], int size) { 2 | int prod = 1; 3 | while (--size) prod *= number[size]; 4 | return prod; 5 | } -------------------------------------------------------------------------------- /code/rc8init/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "iostream": "cpp", 4 | "iosfwd": "cpp", 5 | "xstring": "cpp" 6 | } 7 | } -------------------------------------------------------------------------------- /code/rc10synthesize/base.h: -------------------------------------------------------------------------------- 1 | // base.h 2 | class Base { 3 | string str; 4 | public: 5 | Base() { cout << "default base\n"; } 6 | Base(const Base& other) { cout << "copy base\n"; } 7 | }; -------------------------------------------------------------------------------- /code/rc3build/sum_large.c: -------------------------------------------------------------------------------- 1 | int _Z6reducePii(int* number, int size) { 2 | int sum = 0; 3 | while (--size) 4 | if (number[size] > 3) sum += number[size]; 5 | return sum; 6 | } -------------------------------------------------------------------------------- /code/rc5pz2/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int foo(int x) { 4 | if (x < 100) { x = x * x; foo(x);} 5 | else return x; 6 | } 7 | int main() { cout << foo(15);} 8 | -------------------------------------------------------------------------------- /code/rc2xm/run/xm.in: -------------------------------------------------------------------------------- 1 | xd 2 | cg 3 | hss 4 | xtt 5 | qs 6 | jcc 7 | xdtql 8 | zdnxd 9 | xmxd 10 | xmcg 11 | xmhss 12 | xmxtt 13 | xmqs 14 | xmjcc 15 | xmxdtql 16 | xmzdnxd 17 | -------------------------------------------------------------------------------- /code/rc2xm/xm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | std::string str; 4 | while(std::getline(std::cin, str)) 5 | std::cout << "xm" << str << std::endl; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /code/rc5pz1/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct S{int x = 4; char a[4];}; 4 | void foo() { 5 | S s; cin >> s.a; 6 | while(--s.x) cout << s.a << endl; 7 | } 8 | int main() {foo();} 9 | -------------------------------------------------------------------------------- /code/Linked-List/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "xstring": "cpp", 4 | "xutility": "cpp", 5 | "utility": "cpp", 6 | "system_error": "cpp" 7 | } 8 | } -------------------------------------------------------------------------------- /code/rc10virtual/vtable_qux.cpp: -------------------------------------------------------------------------------- 1 | struct Qux { 2 | struct Baz { 3 | struct Bar { 4 | struct Foo { 5 | vtbl f() = Qux::f; 6 | vtbl g() = Baz::g; 7 | } 8 | } 9 | vtbl h() = Qux::h 10 | } 11 | } -------------------------------------------------------------------------------- /code/rc10access/protected.h: -------------------------------------------------------------------------------- 1 | class Base { protected: int i; int prot();}; 2 | class Derived : public Base { 3 | void bothOK() { i = 0; prot(); /* OK */ } 4 | } derived; 5 | void bothError () { derived.i = 0; derived.prot(); }; -------------------------------------------------------------------------------- /code/rc5unroll/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | #include "file.h" 4 | int foo() { 5 | File f1("file1.in"); File f2("file2.in"); 6 | cout << "I Returned!" << endl; 7 | } 8 | int main() { foo(); } -------------------------------------------------------------------------------- /code/rc5pz3/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | void secretFunction() { 4 | cout << "You shouldn't be here..." << endl; 5 | } 6 | void echo() { char buffer[20]; cin >> buffer; } 7 | int main() { echo(); return 0; } -------------------------------------------------------------------------------- /code/rc5unroll/file.h: -------------------------------------------------------------------------------- 1 | class File { 2 | string name; 3 | public: 4 | File(string file) : name(file) { 5 | cout << "Opended : " << name << endl; } 6 | ~File() { 7 | cout << "Closed " << name << endl; } 8 | }; 9 | -------------------------------------------------------------------------------- /code/rc8class/integer.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGER_H_ 2 | #define _INTEGER_H_ 3 | class Integer { 4 | int value; 5 | public: 6 | int get() const { 7 | return value; 8 | } 9 | void set(int v); 10 | }; 11 | #endif -------------------------------------------------------------------------------- /code/rc3init/init_arr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int arr2[500]; 7 | 8 | for (int i = 0; i < sizeof(arr2) / sizeof(*arr2); i++) { 9 | cout << arr2[i] << endl; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /code/rc3arr/arr.cpp: -------------------------------------------------------------------------------- 1 | template 2 | int GetArrLength(T(&)[size]){ 3 | return size; 4 | } 5 | 6 | int main() { 7 | int x[10]; 8 | int y[11]; 9 | int z[20]; 10 | GetArrLength(x); 11 | GetArrLength(y); 12 | GetArrLength(z); 13 | } 14 | -------------------------------------------------------------------------------- /code/rc8intset/intset.h: -------------------------------------------------------------------------------- 1 | const int MAXELTS = 100; 2 | class IntSet { 3 | int elts[MAXELTS], numElts; 4 | int indOf(int v) const; 5 | public: 6 | void insert(int v); 7 | void remove(int v); 8 | bool query(int v) const; 9 | int size() const; 10 | }; -------------------------------------------------------------------------------- /code/rc9dtor1/ex3.cpp: -------------------------------------------------------------------------------- 1 | //ex3.cpp 2 | #include "classes.h" 3 | 4 | void foo() { 5 | Base* ptrA = new Derived; 6 | delete ptrA; // Safe! 7 | } 8 | 9 | void foo() { 10 | Derived* ptrB = new Derived; 11 | delete ptrB; // Safe! 12 | } 13 | -------------------------------------------------------------------------------- /code/rc3build/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | extern int number[], size; 4 | int reduce(int n[], int s); 5 | int main() { 6 | for (int i=0; i 2 | using namespace std; 3 | struct S {int x; char y[5];}; 4 | void foo() { 5 | S s; cout << &s.x << endl; 6 | cout << (void*)s.y << endl; 7 | cin >> s.y; while(--x) cout << s.x << endl; 8 | } 9 | int main() {foo();} 10 | -------------------------------------------------------------------------------- /code/rc5pz25/a.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int setFirst(x[][5], int size) { 4 | int cheese = 0; 5 | while (size >= 0) x[--size][0] = size; 6 | cout << cheese << endl; 7 | } 8 | int main() { 9 | int arr[10][5] = {0}; 10 | setFirst(arr, 10); 11 | } 12 | -------------------------------------------------------------------------------- /code/rc8class/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "integer.h" 3 | using namespace std; 4 | void dec(Integer&); void inc(Integer&); 5 | int main() { 6 | Integer i; i.set(10); cout << i.get() << " "; 7 | inc(i); cout << i.get() << " "; 8 | dec(i); cout << i.get() << endl; 9 | } 10 | -------------------------------------------------------------------------------- /code/rc9raii/ex.cpp: -------------------------------------------------------------------------------- 1 | // driver.cpp 2 | #include "ex.h" 3 | class T { 4 | IntSet s1, s2; 5 | // ommit other 6 | } 7 | // Nothing leaks 8 | void foo() { 9 | IntSet s; 10 | while (...) { 11 | T t; if (...) throw -1; 12 | } 13 | if (...) return; 14 | else ...; 15 | } -------------------------------------------------------------------------------- /macro.sty: -------------------------------------------------------------------------------- 1 | \newcommand{\twocolumncodenamed}[2]{ 2 | \begin{columns} 3 | \column[]{.5\textwidth} 4 | 5 | \vspace{-.2in} 6 | \inputminted[fontsize=\small]{c++}{#1} 7 | 8 | \column[]{.5\textwidth} 9 | 10 | \vspace{-.2in} 11 | \inputminted[fontsize=\small]{c++}{#2} 12 | \end{columns} 13 | } -------------------------------------------------------------------------------- /code/rc8init/intset_ctor.h: -------------------------------------------------------------------------------- 1 | class IntSet { 2 | // .... 3 | public: 4 | // .... 5 | IntSet() : numElts(0) {} 6 | // Intialize an empty set 7 | IntSet(int v); 8 | // Init. a set with 1 elt 9 | // provided in the arg 10 | }; 11 | IntSet::IntSet(int v) 12 | : numElts(1) { 13 | elts[0] = v; 14 | } -------------------------------------------------------------------------------- /code/rc10virtual/call.cpp: -------------------------------------------------------------------------------- 1 | Bar bar; bar.g(); // Bar::g 2 | Qux qux; qux.g(); // Baz::g 3 | Baz baz; baz.h(); // Baz::h 4 | Foo& f1 = qux; f1.g(); 5 | // Baz::g 6 | Bar& b1 = qux; b1.h(); 7 | // Bar::h 8 | Baz& b2 = qux; b2.h(); 9 | // Qux::h 10 | Bar* bar = &Quz; bar->h(); 11 | // ? 12 | const Foo& cbar = Baz; 13 | cbar.g(); // ? -------------------------------------------------------------------------------- /code/rc8init/oddintset.cpp: -------------------------------------------------------------------------------- 1 | #include "oddintset.h" 2 | #include 3 | using namespace std; 4 | 5 | OddIntSet::OddIntSet() 6 | : numElts(0) { 7 | cout << "OddIntSet dft ctor\n"; 8 | } 9 | 10 | OddIntSet::OddIntSet(int v) 11 | : numElts(0) { 12 | this->insert(v) 13 | cout << "OddIntSet elt ctor\n"; 14 | } -------------------------------------------------------------------------------- /code/rc8intset/intset_ctor.h: -------------------------------------------------------------------------------- 1 | class IntSet { 2 | // .... 3 | public: 4 | // .... 5 | IntSet() : numElts(0) {} 6 | // Intialize an empty set 7 | IntSet(int v); 8 | // Init. a set with 1 elt 9 | // provided in the arg 10 | }; 11 | IntSet::IntSet(int v) 12 | : numElts(1) { 13 | elts[0] = v; 14 | } -------------------------------------------------------------------------------- /code/rc9cpctor/ex1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | class A { 5 | public: 6 | A(const A& a) { 7 | cout << "Copy A" << endl; 8 | } 9 | }; 10 | class B { 11 | A a; 12 | public: 13 | B() = default; 14 | B (const B& b) : a(b.a) {} 15 | }; 16 | int main() { 17 | B b; 18 | B bp(b); 19 | } -------------------------------------------------------------------------------- /code/rc9dtor1/classes.h: -------------------------------------------------------------------------------- 1 | //classes.h 2 | class Base { 3 | protected: 4 | int *p; 5 | public: 6 | Base() : p(new int(10)) {} 7 | ~Base() {delete p;} 8 | }; 9 | 10 | class Derived : public Base { 11 | int *q; 12 | public: 13 | Derived() : 14 | Base(), q(new int(20)) {} 15 | ~Derived() {delete q;} 16 | }; -------------------------------------------------------------------------------- /code/rc11cp/poly.cpp: -------------------------------------------------------------------------------- 1 | #define SWAP(type) swap_##type 2 | #define SWAP_IMPL(type) \ 3 | static void SWAP(type) (type &x, type &y) {\ 4 | type t = x; x = y; y = x; \ 5 | } 6 | SWAP_IMPL(int); 7 | SWAP_IMPL(double); 8 | int main() { 9 | int x =10, y =20; SWAP(int)(x, y); 10 | double p = 0.0, q = 1.0; SWAP(double)(p, q); 11 | } -------------------------------------------------------------------------------- /code/rc9dtor1/ex3.h: -------------------------------------------------------------------------------- 1 | //ex3.h 2 | class Base { 3 | protected: 4 | int *p; 5 | public: 6 | Base() : p(new int(10)) {} 7 | virtual ~Base(){delete p;} 8 | }; 9 | 10 | class Derived : public Base { 11 | int *q; 12 | public: 13 | Derived() : 14 | Base(), q(new int(20)) {} 15 | ~Derived() {delete q;} 16 | }; 17 | -------------------------------------------------------------------------------- /code/rc7writetree/writetree.cpp: -------------------------------------------------------------------------------- 1 | std::ostream& 2 | operator<<(std::ostream &stream, const tree_t &tree) { 3 | if (tree_isEmpty(tree)) { 4 | stream << "$ "; 5 | return stream; } 6 | stream << "[ " << tree_elt(tree) << " "; 7 | stream << tree_left(tree) << ""; 8 | stream << tree_right(tree) << "] "; 9 | return stream; } 10 | -------------------------------------------------------------------------------- /code/rc10compatible/class.h: -------------------------------------------------------------------------------- 1 | // class.h 2 | class Base { 3 | public: string str; 4 | Base(const Base& base) 5 | : str(base.str) { 6 | cout << "cp Base\n"; } 7 | void print() { 8 | cout << a << endl; } 9 | }; 10 | class Derived : public Base { 11 | public: // ... 12 | Derived(const Derived& d) 13 | : Base(d) { 14 | cout << "cp Derived\n"; } 15 | }; -------------------------------------------------------------------------------- /code/rc2xm/run/xm2.in: -------------------------------------------------------------------------------- 1 | xd 2 | cg 3 | hss 4 | xtt 5 | qs 6 | jcc 7 | xdtql 8 | zdnxd 9 | xd 10 | cg 11 | hss 12 | xtt 13 | qs 14 | jcc 15 | xdtql 16 | zdnxd 17 | xmxd 18 | xmcg 19 | xmhss 20 | xmxtt 21 | xmqs 22 | xmjcc 23 | xmxdtql 24 | xmzdnxd 25 | xmxd 26 | xmcg 27 | xmhss 28 | xmxtt 29 | xmqs 30 | xmjcc 31 | xmxdtql 32 | xmzdnxd 33 | -------------------------------------------------------------------------------- /code/rc8init/fastintset.cpp: -------------------------------------------------------------------------------- 1 | #include "fastintset.h" 2 | #include 3 | using namespace std; 4 | 5 | FastIntSet::FastIntSet() 6 | : oddSet(), evenSet(10) { 7 | cout << "fIntSet ctor\n"; 8 | } 9 | 10 | FastIntSet::insert(int v) { 11 | if (isOdd(v)) 12 | oddSet.insert(v); 13 | else 14 | evenSet.insert(v); 15 | } -------------------------------------------------------------------------------- /code/rc9raii/ex.h: -------------------------------------------------------------------------------- 1 | // intset.h 2 | const int MAXELTS = 100; 3 | class IntSet { 4 | int *elts, sizeElts; 5 | int numElts; 6 | public: 7 | IntSet(int size = MAXELTS) 8 | : elts(new int[size]), 9 | sizeElts(size), 10 | numElts(0) {} 11 | 12 | ~IntSet() { delete[] elts;} 13 | // Other methods unchanged 14 | }; -------------------------------------------------------------------------------- /code/rc10access/private.h: -------------------------------------------------------------------------------- 1 | class Base { ... }; 2 | class Derived : private Base { 3 | void bothError() { priv = 0; privMethod(); /* Error */ } 4 | void bothOK() { pub = 0; pubMethod(); /* OK */ } 5 | } derived; 6 | void test() { 7 | derived.priv = 0; /* Error */ derived.privMethod(); /* Error */ 8 | derived.pub = 0; /* Error */ derived.pubMethod(); /* Error */ 9 | }; -------------------------------------------------------------------------------- /code/rc9dtor1/ex2.h: -------------------------------------------------------------------------------- 1 | //ex2.h 2 | class Base { 3 | protected: 4 | int *p; 5 | public: 6 | Base() : p(new int(10)) {} 7 | virtual ~Base(){delete p;} 8 | }; 9 | 10 | class Derived : public Base { 11 | int *q; 12 | public: 13 | Derived() : 14 | Base(), q(new int(20)) {} 15 | ~Derived() 16 | { delete q; delete p;} 17 | }; 18 | -------------------------------------------------------------------------------- /code/rc10synthesize/ok.cpp: -------------------------------------------------------------------------------- 1 | // ok.cpp 2 | class Derived1 : public Base {}; 3 | class Derived2 : public Base { 4 | public: Derived2() = default; 5 | Derived2(const Derived2& d2) : Base(d2) { 6 | cout << "copy derived 2\n"; } }; 7 | int main() { 8 | Derived1 d1; Derived1 d1c(d1); /* cp base */ 9 | Derived2 d2; Derived2 d2c(d2); /* cp base; cp d2 */ } 10 | -------------------------------------------------------------------------------- /code/rc8init/fastintset.h: -------------------------------------------------------------------------------- 1 | #ifndef _FAST_INT_SET_H_ 2 | #define _FAST_INT_SET_H_ 3 | #include "oddintset.h" 4 | #include "evenintset.h" 5 | class FastIntSet { 6 | OddIntSet oddSet; 7 | EvenIntSet evenSet; 8 | public: 9 | FastIntSet(); 10 | void insert(int v); 11 | void remove(int v); 12 | bool query(int v) const; 13 | int size() const; 14 | }; 15 | #endif -------------------------------------------------------------------------------- /code/rc8init/oddintset.h: -------------------------------------------------------------------------------- 1 | #ifndef _ODD_INT_SET_H_ 2 | #define _ODD_INT_SET_H_ 3 | const int MAXELTS = 100; 4 | class OddIntSet { 5 | int elts[MAXELTS], numElts; 6 | int indOf(int v) const; 7 | public: 8 | OddIntSet(); 9 | OddIntSet(int v); 10 | void insert(int v); 11 | void remove(int v); 12 | bool query(int v) const; 13 | int size() const; 14 | }; 15 | #endif -------------------------------------------------------------------------------- /code/rc10virtual/class.h: -------------------------------------------------------------------------------- 1 | struct Foo { 2 | virtual void f() = 0; 3 | virtual void g() = 0; 4 | }; 5 | struct Bar : public Foo { 6 | void f() {}; 7 | void g() {}; 8 | void h() {}; 9 | }; 10 | struct Baz : public Bar { 11 | void f() {}; 12 | void g() {}; 13 | virtual void h() {}; }; 14 | struct Qux : public Baz { 15 | void f() {}; 16 | void h() {}; }; -------------------------------------------------------------------------------- /code/rc10compatible/copy.cpp: -------------------------------------------------------------------------------- 1 | // copy.cpp 2 | void test() { 3 | Derived d; d.a = "hello"; 4 | Base b = d; /* cp Base */ 5 | passByVal(d); 6 | /* cp Base; hellofoo; */ 7 | d.print() /* hello */ 8 | Derived d2 = d; 9 | /* cp Base; cp Derived; */ 10 | Derived d2 = b; /* Error */ 11 | } 12 | 13 | void passByVal(Base base) { 14 | base.str += "foo"; 15 | base.print(); } 16 | -------------------------------------------------------------------------------- /code/rc8const/class.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; // BAD PRACTICE! 4 | class Foo { 5 | int value; 6 | public: 7 | void bar() const { 8 | cout << typeid(this).name() << endl; 9 | cout << typeid(value).name() << endl; 10 | } 11 | void baz() { 12 | cout << typeid(this).name() << endl; 13 | cout << typeid(value).name() << endl; 14 | } 15 | }; -------------------------------------------------------------------------------- /code/rc10access/public.h: -------------------------------------------------------------------------------- 1 | class Base { 2 | private: int priv; void privMethod(); 3 | public: int pub; void pubMethod(); }; 4 | class Derived : public Base { 5 | void bothError() { priv = 0; privMethod(); /* Error */ } 6 | void bothOK() { pub = 0; pubMethod(); /* OK */ } 7 | } derived; 8 | void bothError() { derived.priv = 0; derived.privMethod(); } 9 | void bothOK () { derived.pub = 0; derived.pubMethod(); } -------------------------------------------------------------------------------- /code/rc4fptr/fptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int add (int x, int y) {return x + y;} 3 | int subtract(int x, int y) {return x - y;} 4 | int (*fun[])(int, int) = {add, subtract}; 5 | using namespace std; 6 | int main() { 7 | int op = 1, x = 0, y = 0; 8 | cout << "Select your operation (1,2): "; cin >> op; 9 | cout << "Numbers: "; cin >> x >> y; 10 | cout << "ANS = " << fun[op-1](x, y) << endl; 11 | } -------------------------------------------------------------------------------- /code/rc8init/intset.cpp: -------------------------------------------------------------------------------- 1 | int 2 | IntSet::indOf(int v) const { 3 | // Omit implementating 4 | // Not found return MAXELTS 5 | } 6 | void IntSet::insert(int v) { 7 | if (indOf(v) != MAXELTS) { 8 | assert(numElts < 100); 9 | elts[numElts++] = v; 10 | } 11 | } 12 | void IntSet::remove(int v) { 13 | int vic = indOf(v); 14 | if (vic != MAXELTS) { 15 | elts[vic]=elts[numElts-1]; 16 | numElts--; 17 | } 18 | } -------------------------------------------------------------------------------- /code/rc8intset/intset.cpp: -------------------------------------------------------------------------------- 1 | int 2 | IntSet::indOf(int v) const { 3 | // Omit implementating 4 | // Not found return MAXELTS 5 | } 6 | void IntSet::insert(int v) { 7 | if (indOf(v) != MAXELTS) { 8 | assert(numElts < 100); 9 | elts[numElts++] = v; 10 | } 11 | } 12 | void IntSet::remove(int v) { 13 | int vic = indOf(v); 14 | if (vic != MAXELTS) { 15 | elts[vic]=elts[numElts-1]; 16 | numElts--; 17 | } 18 | } -------------------------------------------------------------------------------- /code/rc3build/Makefile: -------------------------------------------------------------------------------- 1 | all : sum_even 2 | sum_even : objects 3 | g++ -o run main.o even.o sum.o 4 | prod_odd : objects 5 | g++ -o run main.o prod.o odd.o 6 | clean : 7 | rm -f *.o && rm -f ./run 8 | onestep : main.cpp even.cpp sum.cpp 9 | g++ -o run main.cpp even.cpp sum.cpp 10 | objects : sum.cpp prod.cpp even.cpp odd.cpp main.cpp 11 | g++ -c sum.cpp && g++ -c prod.cpp 12 | g++ -c even.cpp && g++ -c odd.cpp 13 | g++ -c main.cpp 14 | 15 | 16 | -------------------------------------------------------------------------------- /code/rc8this/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | class Natural { 6 | int value; 7 | public: 8 | int get() { return value; } 9 | void set(int value) { 10 | this->value = value; 11 | } 12 | void printThis() { 13 | cout << this << endl; 14 | } 15 | }; 16 | 17 | int main() { 18 | Natural n1; 19 | Natural n2; 20 | cout << &n1 << endl; 21 | n1.printThis(); 22 | cout << &n2 << endl; 23 | n2.printThis(); 24 | } 25 | -------------------------------------------------------------------------------- /code/rc8const/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; // BAD PRACTICE! 4 | class Foo { 5 | int value; 6 | public: 7 | void bar() const { 8 | cout << typeid(this).name() << endl; 9 | cout << typeid(&value).name() << endl; 10 | } 11 | void baz() { 12 | cout << typeid(this).name() << endl; 13 | cout << typeid(&value).name() << endl; 14 | } 15 | }; 16 | int main() { Foo x; x.bar(); x.baz(); } -------------------------------------------------------------------------------- /code/rc10compatible/class.cpp: -------------------------------------------------------------------------------- 1 | // class.cpp 2 | void test() { 3 | Derived d; d.a = "hello"; 4 | d.print(); /* hello */ 5 | Base* bp = &d; bp->a = "ha"; 6 | d.print(); /* ha */ 7 | bad(&d); d.print(); /* bad */ 8 | good(d); d.print(); /* good */ 9 | pbase(d); /* good */ 10 | } 11 | void bad(Base* base) { 12 | base->a += "bad"; } 13 | void good(Base& base) { 14 | base.a += "good"; } 15 | void pbase(const Base& base) { 16 | base.print();} -------------------------------------------------------------------------------- /code/rc10synthesize/error.cpp: -------------------------------------------------------------------------------- 1 | // error.cpp 2 | class Derived3 : public Base { 3 | public: Derived3(const Derived3& d3) : Base(d3) { 4 | cout << "copy derived 3\n"; } }; 5 | class Derived4 : public Base { 6 | public: Derived4() = default; 7 | Derived4(const Derived4& d4) { 8 | cout << "copy derived 4\n"; } }; 9 | int main() { 10 | Derived1 d3; Derived1 d3c(d3); /* Compile Error */ 11 | Derived2 d4; Derived4 d2c(d4); /* dft base; cp d4 */} 12 | 13 | -------------------------------------------------------------------------------- /code/rc3init/init_str.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | struct S { 6 | int x, y; 7 | int arr[3]; 8 | double d; 9 | }; 10 | 11 | int main() { 12 | int x[] = {1, 2, 4, 5, 6}; 13 | S s{1, 2, {3, 4, 5}, 6.0}; 14 | cout << s.x << " " << s.y << endl; 15 | cout << s.arr[0] << " " << s.arr[1] << " " << s.arr[2] << endl; 16 | cout << s.d << endl; 17 | S a[2] = { 18 | {1, 2, {3, 4, 5}, 6.0}, 19 | {2, 3, {3, 4, 6}, 4.0} 20 | }; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /code/rc9sgt/sgt.h: -------------------------------------------------------------------------------- 1 | // s.h 2 | class S { 3 | static S* instance; 4 | S() {} // Constructor 5 | public: 6 | static S& getInstance() { 7 | if (instance == nullptr) instance = new S; 8 | return *s; 9 | } 10 | S(S const&) = delete; 11 | S& operator=(S const&) = delete; 12 | }; 13 | // s.cpp 14 | S* S::instance = nullptr; // initialize 15 | // foo.cpp 16 | void foo() { S& s = S::getInstance(); /* Use s as you wish */} -------------------------------------------------------------------------------- /code/rc3arr/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo 'We will now compile arr.cpp into arr.o' 4 | g++ -c -O0 arr.cpp 5 | echo 'The content of arr.cpp is given as follows' 6 | echo '===== arr.cpp ====' 7 | cat arr.cpp 8 | echo '==================' 9 | echo 'The template is instantiated once for each type' 10 | echo 'We expect to see the template be instantiated three times' 11 | echo '===== nm arr.o ====' 12 | nm arr.o 13 | echo '===================' 14 | echo 'Now we see the template is instantiated 3 times' 15 | echo 'Notice the size of array becomes part of tempate instantiation' 16 | -------------------------------------------------------------------------------- /code/Linked-List/IntList.h: -------------------------------------------------------------------------------- 1 | class listIsEmpty {}; // An exception class 2 | struct node{ node *next; int value; }; 3 | class IntList { 4 | node *first; 5 | void removeAll(); 6 | void copyList(node *list); 7 | public: 8 | bool isEmpty() const; 9 | void insert(int v); // inserts v into the front of the list 10 | int remove(); // Pops the first element 11 | void print() const; // print the int list 12 | IntList(); // default constructor 13 | IntList(const IntList& l); // copy constructor 14 | ~IntList(); // destructor 15 | IntList &operator=(const IntList &l); // assignment operator 16 | }; -------------------------------------------------------------------------------- /code/rc5qsort/nonrec.cpp: -------------------------------------------------------------------------------- 1 | void quickSort(int *data, int left, int right) { 2 | int len = right - left; if (len <= 1) return; 3 | int pivotIndex = left; int pivot = data[pivotIndex]; 4 | int *pData = new int[len]; 5 | int top = 0; int bottom = len - 1; 6 | for (int i = left; i < right; ++i) { 7 | if (i == pivotIndex) continue; 8 | if (data[i] <= pivot) pData[top++] = data[i]; 9 | if (data[i] > pivot) pData[bottom--] = data[i]; 10 | } pData[top] = pivot; 11 | for (int j=0; j 2 | #include "IntList.h" 3 | using namespace std; 4 | 5 | void foo(IntList x) 6 | { 7 | cout << "Print copy in function foo" << endl; 8 | x.print(); 9 | } 10 | 11 | int main() 12 | { 13 | IntList s; 14 | cout << "Insert 1 at the front" << endl; 15 | s.insert(1); 16 | cout << "Insert 2 at the front" << endl; 17 | s.insert(2); 18 | cout << "Insert 3 at the front" << endl; 19 | s.insert(3); 20 | s.print(); 21 | 22 | foo(s); 23 | 24 | { 25 | IntList x; 26 | x = s; 27 | cout << "Print copy by assignment" << endl; 28 | x.print(); 29 | } 30 | 31 | cout << "Remove the first item" << endl; 32 | s.remove(); 33 | s.print(); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/IntSet-Default-Argument/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "IntSet.h" 3 | 4 | using namespace std; 5 | 6 | int main() 7 | { 8 | //IntSet bar; // capacity is MAXELTS 9 | IntSet foo(50); 10 | cout << "insert 7" << endl; 11 | foo.insert(7); 12 | foo.print(); 13 | 14 | cout << "insert 3" << endl; 15 | foo.insert(3); 16 | foo.print(); 17 | 18 | cout << "insert 4" << endl; 19 | foo.insert(4); 20 | foo.print(); 21 | 22 | cout << "insert 5" << endl; 23 | foo.insert(5); 24 | foo.print(); 25 | 26 | cout << "insert 7" << endl; 27 | foo.insert(7); 28 | foo.print(); 29 | 30 | cout << "insert 8" << endl; 31 | foo.insert(8); 32 | foo.print(); 33 | 34 | cout << "remove 5" << endl; 35 | foo.remove(5); 36 | foo.print(); 37 | 38 | cout << "remove 8" << endl; 39 | foo.remove(8); 40 | foo.print(); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /code/IntSet-Default-Argument/IntSet.cpp: -------------------------------------------------------------------------------- 1 | #include "IntSet.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | IntSet::IntSet(int size): elts(new int[size]), 7 | sizeElts(size), numElts(0) 8 | { 9 | } 10 | 11 | int IntSet::indexOf(int v) 12 | { 13 | for (int i = 0; i < numElts; i++) 14 | { 15 | if (elts[i] == v) 16 | return i; 17 | } 18 | return sizeElts; 19 | } 20 | 21 | int IntSet::size() 22 | { 23 | return numElts; 24 | } 25 | 26 | bool IntSet::query(int v) 27 | { 28 | return (indexOf(v) != sizeElts); 29 | } 30 | 31 | void IntSet::insert(int v) 32 | { 33 | if (indexOf(v) == sizeElts) 34 | { 35 | if (numElts == sizeElts) 36 | throw sizeElts; 37 | elts[numElts++] = v; 38 | } 39 | } 40 | 41 | void IntSet::remove(int v) 42 | { 43 | int victim = indexOf(v); 44 | if (victim != sizeElts) 45 | { 46 | elts[victim] = elts[numElts-1]; 47 | numElts--; 48 | } 49 | else 50 | { 51 | throw v; 52 | } 53 | } 54 | 55 | void IntSet::print() 56 | { 57 | for (int i = 0; i < numElts; i++) 58 | { 59 | cout << elts[i] << " " << flush; 60 | } 61 | cout << endl; 62 | } 63 | -------------------------------------------------------------------------------- /code/IntSet-Default-Argument/IntSet.h: -------------------------------------------------------------------------------- 1 | #ifndef INTSET_H 2 | #define INTSET_H 3 | 4 | const int MAXELTS = 100; 5 | 6 | 7 | class IntSet 8 | { 9 | // OVERVIEW: a mutable set of integers, |set| <= sizeElts 10 | int *elts; // pointer to dynamic array 11 | int sizeElts; // capacity of array 12 | int numElts; // current occupancy 13 | 14 | int indexOf(int v); 15 | // EFFECTS: returns the index of v if it exists in the 16 | // array, sizeElts otherwise. 17 | 18 | public: 19 | IntSet(int size = MAXELTS); 20 | // EFFECTS: create a set with specified capacity. 21 | // It defaults to MAXELTS if not supplied. 22 | void insert(int v); 23 | // MODIFIES: this 24 | // EFFECTS: this = this + {v} if room, 25 | // throws int sizeElts otherwise. 26 | void remove(int v); 27 | // MODIFIES: this 28 | // EFFECTS: this = this - {v} if v is in this 29 | // throws int v otherwise. 30 | bool query(int v); 31 | // EFFECTS: returns true if v is in this, false otherwise. 32 | int size(); 33 | // EFFECTS: returns |this|. 34 | void print(); 35 | // MODIFIES: cout 36 | // EFFECTS: print out the integers contained in the set in 37 | // sequence. 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VE280-Notes 2 | Recitation class lecture notes for VE280 3 | 4 | # Build 5 | 6 | LaTeX package `minted` is used to highlight the code in this project. 7 | 8 | In order to make it work, you should add `-shell-escape` option to your latex compiler, and install the python package `Pygments` if you are to build 9 | this directly. 10 | 11 | Alternatively with the dependencies install simply `make` and you should find a built copy under `build/`. 12 | 13 | A copy of the built pdf is committed into the repo so people can read without cloning. The content is outdated, and frankly somewhat unpolished with the benefit of the hindsight but I think this should be left in for the sake of maintaining an honest history. 14 | 15 | # Notice for Other Users: 16 | 17 | This repository was created mainly as a place to for me to backup my work. It was never my intention for those slides to be used by anyone other than me, but things have evolved to the place that this work will benefit other people, specifically future TAs for the course. 18 | 19 | The contents of this repository from the very begginning is Licensed under GPL 3.0, therefore naturally grants anyone who wishes to utilize the content to use it as they wish. No explicit permissions required. However, I ask that future TAs of the course inform me that they are using it, and if they add to / have comments on any of the chapters, please also contribute your work here. As you already know there are unfished chapters and things tends to get much worse towards the last chapters. 20 | -------------------------------------------------------------------------------- /code/Linked-List/IntList.cpp: -------------------------------------------------------------------------------- 1 | #include "IntList.h" 2 | #include 3 | using namespace std; 4 | 5 | bool IntList::isEmpty() const { 6 | return first == nullptr; 7 | } 8 | 9 | IntList::IntList(): first(nullptr) {} 10 | 11 | IntList::~IntList() { removeAll(); } 12 | 13 | void IntList::removeAll() { 14 | while(!isEmpty()) remove(); 15 | } 16 | 17 | void IntList::insert(int v){ 18 | node *np = new node; // Gaining Ownership 19 | np->value = v; 20 | np->next = first; // Keep it in mind! 21 | first = np; // Also keep that in mind! 22 | } 23 | int IntList::remove() { 24 | if (isEmpty()) throw listIsEmpty(); 25 | int result = first->value; // None empty, always possible 26 | node *victim = first; // Whay save to victim? 27 | first = first->next; 28 | delete victim; // Giving up ownership 29 | return result; // Value container 30 | } 31 | 32 | IntList::IntList(const IntList &l) 33 | : first (0) { 34 | copyList(l.first); 35 | } 36 | 37 | void IntList::copyList(node *list) { 38 | if (!list) return; // Base case 39 | copyList(list->next); 40 | insert(list->value); 41 | } 42 | 43 | 44 | IntList &IntList::operator= (const IntList &l) { 45 | if (this != &l) { 46 | removeAll(); 47 | copyList(l.first); 48 | } 49 | return *this; 50 | } 51 | 52 | void IntList::print() const { 53 | node *p = first; 54 | while(p) 55 | { 56 | cout << p->value << " "; 57 | p = p->next; 58 | } 59 | cout << endl; 60 | } 61 | -------------------------------------------------------------------------------- /code/rc2xm/run/out: -------------------------------------------------------------------------------- 1 | xmxd 2 | xmcg 3 | xmhss 4 | xmxtt 5 | xmqs 6 | xmjcc 7 | xmxdtql 8 | xmzdnxd 9 | xmxd 10 | xmcg 11 | xmhss 12 | xmxtt 13 | xmqs 14 | xmjcc 15 | xmxdtql 16 | xmzdnxd 17 | xmxmxd 18 | xmxmcg 19 | xmxmhss 20 | xmxmxtt 21 | xmxmqs 22 | xmxmjcc 23 | xmxmxdtql 24 | xmxmzdnxd 25 | xmxmxd 26 | xmxmcg 27 | xmxmhss 28 | xmxmxtt 29 | xmxmqs 30 | xmxmjcc 31 | xmxmxdtql 32 | xmxmzdnxd 33 | xmxd 34 | xmcg 35 | xmhss 36 | xmxtt 37 | xmqs 38 | xmjcc 39 | xmxdtql 40 | xmzdnxd 41 | xmxd 42 | xmcg 43 | xmhss 44 | xmxtt 45 | xmqs 46 | xmjcc 47 | xmxdtql 48 | xmzdnxd 49 | xmxmxd 50 | xmxmcg 51 | xmxmhss 52 | xmxmxtt 53 | xmxmqs 54 | xmxmjcc 55 | xmxmxdtql 56 | xmxmzdnxd 57 | xmxmxd 58 | xmxmcg 59 | xmxmhss 60 | xmxmxtt 61 | xmxmqs 62 | xmxmjcc 63 | xmxmxdtql 64 | xmxmzdnxd 65 | xmxd 66 | xmcg 67 | xmhss 68 | xmxtt 69 | xmqs 70 | xmjcc 71 | xmxdtql 72 | xmzdnxd 73 | xmxd 74 | xmcg 75 | xmhss 76 | xmxtt 77 | xmqs 78 | xmjcc 79 | xmxdtql 80 | xmzdnxd 81 | xmxmxd 82 | xmxmcg 83 | xmxmhss 84 | xmxmxtt 85 | xmxmqs 86 | xmxmjcc 87 | xmxmxdtql 88 | xmxmzdnxd 89 | xmxmxd 90 | xmxmcg 91 | xmxmhss 92 | xmxmxtt 93 | xmxmqs 94 | xmxmjcc 95 | xmxmxdtql 96 | xmxmzdnxd 97 | xmxd 98 | xmcg 99 | xmhss 100 | xmxtt 101 | xmqs 102 | xmjcc 103 | xmxdtql 104 | xmzdnxd 105 | xmxd 106 | xmcg 107 | xmhss 108 | xmxtt 109 | xmqs 110 | xmjcc 111 | xmxdtql 112 | xmzdnxd 113 | xmxmxd 114 | xmxmcg 115 | xmxmhss 116 | xmxmxtt 117 | xmxmqs 118 | xmxmjcc 119 | xmxmxdtql 120 | xmxmzdnxd 121 | -------------------------------------------------------------------------------- /main.tex: -------------------------------------------------------------------------------- 1 | \documentclass[slidestop,compress,mathserif]{beamer} 2 | \mode 3 | \beamertemplatenavigationsymbolsempty 4 | \addtobeamertemplate{navigation symbols}{}{% 5 | \usebeamerfont{footline}% 6 | \usebeamercolor[fg]{footline}% 7 | \hspace{5em}% 8 | \textbf{\insertframenumber/\inserttotalframenumber} 9 | } 10 | \usepackage[outputdir=build]{minted} 11 | %\usepackage{minted} 12 | \usepackage{latexsym} 13 | \usepackage{menukeys} 14 | \usepackage{bytefield} 15 | \usepackage{textcomp} 16 | \usepackage{varwidth} 17 | 18 | \usepackage{tikz} 19 | \usetikzlibrary{shapes,arrows} 20 | 21 | \usepackage{macro} 22 | 23 | %\usepackage[bars]{beamerthemetree} % Beamer主题样式v 2.2 24 | \usetheme{Antibes} % Beamer主题样式v 3.0 25 | \usecolortheme{lily} % Beamer颜色主题样式 26 | 27 | \AtBeginSubsection[]{ 28 | \begin{frame} 29 | \vfill 30 | \centering 31 | \begin{beamercolorbox}[sep=8pt,center,shadow=true,rounded=true]{title} 32 | \insertsectionhead\newline\newline\usebeamerfont{title}\insertsubsectionhead\par% 33 | \end{beamercolorbox} 34 | \vfill 35 | \end{frame} 36 | } 37 | 38 | \title{VE280 Recitation Class Notes} 39 | \author{YAO Yue} 40 | \institute{VE280 SU17 TA Group} 41 | \begin{document} 42 | \begin{frame} % Cover slide 43 | \titlepage 44 | 45 | \tiny{Source code available at https://github.com/tripack45/VE280-Notes} 46 | \end{frame} 47 | 48 | \begin{frame}[allowframebreaks] 49 | \small 50 | \frametitle{Table Of Contents} 51 | \tableofcontents 52 | \end{frame} 53 | 54 | \include{week2} 55 | \include{week3} 56 | \include{week4} 57 | \include{week5} 58 | \include{week6} 59 | \include{week7} 60 | \include{week8} 61 | \include{week9} 62 | \include{week10} 63 | \include{week11} 64 | \include{week12} 65 | 66 | \end{document} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Core latex/pdflatex auxiliary files: 2 | *.aux 3 | *.lof 4 | *.log 5 | *.lot 6 | *.fls 7 | *.out 8 | *.toc 9 | *.fmt 10 | *.fot 11 | *.cb 12 | *.cb2 13 | 14 | ## Intermediate documents: 15 | *.dvi 16 | *-converted-to.* 17 | # these rules might exclude image files for figures etc. 18 | # *.ps 19 | # *.eps 20 | # *.pdf 21 | 22 | ## Generated if empty string is given at "Please type another file name for output:" 23 | .pdf 24 | 25 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 26 | *.bbl 27 | *.bcf 28 | *.blg 29 | *-blx.aux 30 | *-blx.bib 31 | *.run.xml 32 | 33 | ## Build tool auxiliary files: 34 | *.fdb_latexmk 35 | *.synctex 36 | *.synctex(busy) 37 | *.synctex.gz 38 | *.synctex.gz(busy) 39 | *.pdfsync 40 | 41 | ## Auxiliary and intermediate files from other packages: 42 | # algorithms 43 | *.alg 44 | *.loa 45 | 46 | # achemso 47 | acs-*.bib 48 | 49 | # amsthm 50 | *.thm 51 | 52 | # beamer 53 | *.nav 54 | *.pre 55 | *.snm 56 | *.vrb 57 | 58 | # changes 59 | *.soc 60 | 61 | # cprotect 62 | *.cpt 63 | 64 | # elsarticle (documentclass of Elsevier journals) 65 | *.spl 66 | 67 | # endnotes 68 | *.ent 69 | 70 | # fixme 71 | *.lox 72 | 73 | # feynmf/feynmp 74 | *.mf 75 | *.mp 76 | *.t[1-9] 77 | *.t[1-9][0-9] 78 | *.tfm 79 | 80 | #(r)(e)ledmac/(r)(e)ledpar 81 | *.end 82 | *.?end 83 | *.[1-9] 84 | *.[1-9][0-9] 85 | *.[1-9][0-9][0-9] 86 | *.[1-9]R 87 | *.[1-9][0-9]R 88 | *.[1-9][0-9][0-9]R 89 | *.eledsec[1-9] 90 | *.eledsec[1-9]R 91 | *.eledsec[1-9][0-9] 92 | *.eledsec[1-9][0-9]R 93 | *.eledsec[1-9][0-9][0-9] 94 | *.eledsec[1-9][0-9][0-9]R 95 | 96 | # glossaries 97 | *.acn 98 | *.acr 99 | *.glg 100 | *.glo 101 | *.gls 102 | *.glsdefs 103 | 104 | # gnuplottex 105 | *-gnuplottex-* 106 | 107 | # gregoriotex 108 | *.gaux 109 | *.gtex 110 | 111 | # hyperref 112 | *.brf 113 | 114 | # knitr 115 | *-concordance.tex 116 | # TODO Comment the next line if you want to keep your tikz graphics files 117 | *.tikz 118 | *-tikzDictionary 119 | 120 | # listings 121 | *.lol 122 | 123 | # makeidx 124 | *.idx 125 | *.ilg 126 | *.ind 127 | *.ist 128 | 129 | # minitoc 130 | *.maf 131 | *.mlf 132 | *.mlt 133 | *.mtc[0-9]* 134 | *.slf[0-9]* 135 | *.slt[0-9]* 136 | *.stc[0-9]* 137 | 138 | # minted 139 | _minted* 140 | *.pyg 141 | 142 | # morewrites 143 | *.mw 144 | 145 | # nomencl 146 | *.nlo 147 | 148 | # pax 149 | *.pax 150 | 151 | # pdfpcnotes 152 | *.pdfpc 153 | 154 | # sagetex 155 | *.sagetex.sage 156 | *.sagetex.py 157 | *.sagetex.scmd 158 | 159 | # scrwfile 160 | *.wrt 161 | 162 | # sympy 163 | *.sout 164 | *.sympy 165 | sympy-plots-for-*.tex/ 166 | 167 | # pdfcomment 168 | *.upa 169 | *.upb 170 | 171 | # pythontex 172 | *.pytxcode 173 | pythontex-files-*/ 174 | 175 | # thmtools 176 | *.loe 177 | 178 | # TikZ & PGF 179 | *.dpth 180 | *.md5 181 | *.auxlock 182 | 183 | # todonotes 184 | *.tdo 185 | 186 | # easy-todo 187 | *.lod 188 | 189 | # xindy 190 | *.xdy 191 | 192 | # xypic precompiled matrices 193 | *.xyc 194 | 195 | # endfloat 196 | *.ttt 197 | *.fff 198 | 199 | # Latexian 200 | TSWLatexianTemp* 201 | 202 | ## Editors: 203 | # WinEdt 204 | *.bak 205 | *.sav 206 | 207 | # Texpad 208 | .texpadtmp 209 | 210 | # Kile 211 | *.backup 212 | 213 | # KBibTeX 214 | *~[0-9]* 215 | 216 | # auto folder when using emacs and auctex 217 | /auto/* 218 | 219 | # expex forward references with \gathertags 220 | *-tags.tex 221 | 222 | ### C++ template 223 | # Prerequisites 224 | *.d 225 | 226 | # Compiled Object files 227 | *.slo 228 | *.lo 229 | *.o 230 | *.obj 231 | 232 | # Precompiled Headers 233 | *.gch 234 | *.pch 235 | 236 | # Compiled Dynamic libraries 237 | *.so 238 | *.dylib 239 | *.dll 240 | 241 | # Fortran module files 242 | *.mod 243 | *.smod 244 | 245 | # Compiled Static libraries 246 | *.lai 247 | *.la 248 | *.a 249 | *.lib 250 | 251 | # Executables 252 | *.exe 253 | *.app 254 | 255 | build/ 256 | code/test 257 | *.zip 258 | .DS_Store 259 | *.o 260 | .vscode 261 | -------------------------------------------------------------------------------- /week12.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 12} 2 | \subsection{Elementary data structures} 3 | \begin{frame}{Data structures 101} 4 | \small 5 | There are always two interleaved concepts when we talk about data structures: 6 | \begin{description}[Implementation] 7 | \item[Abstraction] This is how they are used, for example, as a queue, or as a stack etc. This includes design choices of supporting random access, supporting enumeration etc. 8 | \item[Implementation] This focuses on how the abstraction is implemented. For example a stack can be implemented by a array (if you dynamically resize it), or by a linked list, or by a doubly linked list, or by a hash map or a binary tree. 9 | \end{description} 10 | It is always that you first choose your abstraction base on what you need. Then you decide on the implementation. Of course there sometimes exists sort of "default" implementation, which is reasonably fast on most (if not all) operations. We will learn about them, but remember the that a \texttt{stack} is not always a linked list, but it is most likely to be. 11 | \end{frame} 12 | 13 | \begin{frame}{Measuring performance} 14 | \begin{small} 15 | We need a way of measuring how fast an operation is. We do this by examining \textit{time complexity} of an operation. We will study this in VE281, now we just give you a preliminary idea. Essentially we assume there is $n$ element in the container, and we measure how much time it takes to perform such operation once. 16 | \end{small} 17 | \begin{description}[Exponential] 18 | \item[Super Fast] Means operation takes $O(1)$ (constant time) no matter how many elements in the container. 19 | \item[Fast] $O(\log n)$. The base of the logarithm is irrelavent. 20 | \item[Reasonable] $O(n \log n)$ or $O(n)$. Acceptable for large dataset. 21 | \item[It depends] $O(n^2)$, $(n^3)$. Depends on scale. 22 | \item[Emmmm] Any polynomial with order larger than 3 23 | \item[Exponential] $O(b^n)$ with arbitrary base. Usual operations taking exponential time is not acceptable unless no other methods are available. 24 | \item[NO!NO!NO!] Super exponential algorithms. For example $O(n!)$. 25 | \end{description} 26 | \end{frame} 27 | 28 | \begin{frame}{A stack} 29 | A stack is a sequential data structure that: 30 | \begin{itemize} 31 | \item (Usually super fast) insert and remove at front. 32 | \item Objects first pushed onto the stack comes out last. It is often called First-In-Last-Out. Thus it is often referred as a FILO. 33 | \end{itemize} 34 | It does not (need to) support 35 | \begin{itemize} 36 | \item Any form of random access. i.e. no insert / remove even read in the middle. 37 | \item Enumeration in any order 38 | \item Fast querying of any sort. 39 | \end{itemize} 40 | A stack describes an abstraction. Essentially any implementation that guarantees the above two property (abstraction) can be used to implement a stack. 41 | \end{frame} 42 | 43 | \begin{frame}{A queue} 44 | A stack is a sequential data structure that: 45 | \begin{itemize} 46 | \item (Usually super fast) insert at front. 47 | \item (Usually super fast) remove at \alert{the end}. 48 | \item Objects first pushed onto the stack comes out first. It is often called First-In-\alert{First}-Out. Thus it is often referred as a FILO. 49 | \end{itemize} 50 | It does not (need to) support 51 | \begin{itemize} 52 | \item Any form of random access. i.e. no insert / remove even read in the middle. 53 | \item Enumeration in any order 54 | \item Fast querying of any sort. 55 | \item \alert{Remove at the front and insert at the end.} 56 | \end{itemize} 57 | A queue describes an abstraction. Essentially any implementation that guarantees the above three property (abstraction) can be used to implement a queue. 58 | \end{frame} 59 | 60 | \begin{frame}{A \texttt{deque}} 61 | \texttt{deque} stands for \textit{double ended queue}. A \texttt{deque} is a sequential data structure that: 62 | \begin{itemize} 63 | \item (Usually super fast) insert / remove at front. 64 | \item (Usually super fast) insert / remove at the end. 65 | \item As it's name suggests it looks like a double ended queue. It's hard to rigorously (clear in the sense of mathematics) define what a deque does. 66 | \end{itemize} 67 | It does not (need to) support 68 | \begin{itemize} 69 | \item Any form of random access. i.e. no insert / remove even read in the middle. 70 | \item Enumeration in any order 71 | \item Fast querying of any sort. 72 | \end{itemize} 73 | \end{frame} 74 | 75 | \begin{frame}{Implementation by Linear List} 76 | A \textit{linear list} is simply a fancy name for \texttt{array}. 77 | 78 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{36} 79 | %\bitheader[endianness=little]{0,4,8,12,16,20,24,28,32}\\ 80 | \begin{leftwordgroup}{} 81 | \bitbox[]{8}{}\bitbox[]{12}{} 82 | \bitbox[]{4}{\texttt{count=5}} 83 | \bitbox[]{8}{} 84 | \bitbox[]{4}{\texttt{SIZE=8}} 85 | \end{leftwordgroup}\\ 86 | \begin{leftwordgroup}{data} 87 | \bitbox{4}{\texttt{-1}} 88 | \bitbox{4}{\texttt{3}} 89 | \bitbox{4}{\texttt{80}} 90 | \bitbox{4}{\texttt{2}} 91 | \bitbox{4}{\texttt{9}} 92 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 93 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 94 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 95 | \bitbox[]{4}{} 96 | \end{leftwordgroup}\\ 97 | \begin{leftwordgroup}{} 98 | \bitbox[]{8}{}\bitbox[]{12}{} 99 | \bitbox[]{8}{\textuparrow\quad End} 100 | \end{leftwordgroup}\\ 101 | \end{bytefield} 102 | 103 | \vspace{-.2in} 104 | Note particularly the two boundary cases: 105 | 106 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{36} 107 | %\bitheader[endianness=little]{0,4,8,12,16,20,24,28,32}\\ 108 | \begin{leftwordgroup}{} 109 | \bitbox[]{8}{}\bitbox[]{12}{} 110 | \bitbox[]{4}{} 111 | \bitbox[]{8}{} 112 | \bitbox[]{4}{\texttt{SIZE=8}\\ \texttt{count=8}} 113 | \end{leftwordgroup}\\ 114 | \begin{leftwordgroup}{data} 115 | \bitbox{4}{\texttt{-1}} 116 | \bitbox{4}{\texttt{3}} 117 | \bitbox{4}{\texttt{80}} 118 | \bitbox{4}{\texttt{2}} 119 | \bitbox{4}{\texttt{9}} 120 | \bitbox{4}{\texttt{-2}} 121 | \bitbox{4}{\texttt{2}} 122 | \bitbox{4}{\texttt{1}} 123 | \bitbox[]{4}{} 124 | \end{leftwordgroup}\\ 125 | \begin{leftwordgroup}{} 126 | \bitbox[]{6}{}\bitbox[]{26}{} 127 | \bitbox[]{4}{\textuparrow \space End} 128 | \end{leftwordgroup}\\ 129 | \end{bytefield} 130 | 131 | \vspace{-.2in} 132 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{36} 133 | %\bitheader[endianness=little]{0,4,8,12,16,20,24,28,32}\\ 134 | \begin{leftwordgroup}{} 135 | \bitbox[]{4}{\texttt{count=0}} 136 | \bitbox[]{8}{}\bitbox[]{12}{} 137 | \bitbox[]{8}{} 138 | \bitbox[]{4}{\texttt{SIZE=8}} 139 | \end{leftwordgroup}\\ 140 | \begin{leftwordgroup}{data} 141 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 142 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 143 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 144 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 145 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 146 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 147 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 148 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 149 | \bitbox[]{4}{} 150 | \end{leftwordgroup}\\ 151 | \begin{leftwordgroup}{} 152 | \bitbox[]{8}{\textuparrow End}\bitbox[]{12}{} 153 | 154 | \end{leftwordgroup}\\ 155 | \end{bytefield} 156 | \end{frame} 157 | 158 | \begin{frame}[fragile]{Left close right open convention} 159 | One convention that is used throughout any sequentially iterable data structure is the \textit{Left-close-right-open}. Remember this is more than a direct array. The rule is essentially the following: 160 | \begin{itemize} 161 | \item The end pointer (or anything equivalent) points to one-pass-the-end location. 162 | \item The front pointer points to the first element (if there is one). 163 | \end{itemize} 164 | This rule is so important that the standard is willing to put a syntax hole just for this convention. The standard says: 165 | 166 | \vspace{0.1in} 167 | If you have an array defined in the following manner: 168 | \begin{minted}{c++} 169 | int x[10] = {0}; 170 | \end{minted} 171 | \begin{itemize} 172 | \item \texttt{\&(x[11]) == x + 11}, \texttt{\&(x[11]) - x}, \texttt{\&(x[11]) > x} : are all undefined behavior. 173 | \item \texttt{\&(x[10]) == x + 10}, \texttt{\&(x[10]) - x == 10},\\, \texttt{\&(x[10]) > x} are guaranteed to hold. 174 | \end{itemize} 175 | \end{frame} 176 | 177 | \begin{frame}[fragile]{Left close right open convention} 178 | Following the convention is very beneficial for us: 179 | \begin{itemize} 180 | \item \texttt{end} always puts to the next place to add new elements. 181 | \item Thus \texttt{data[size]} is always the next place to add new elements. 182 | \item \texttt{end - data == size} always hold. 183 | \end{itemize} 184 | 185 | These property are very helpful in keeping track invariants within a class. They are especially very helpful in writing loops 186 | \begin{minted}{c++} 187 | for (int i = 0; i < size; i++) /* Use data[i] */; 188 | \end{minted} 189 | Or in terms of pointer 190 | \begin{minted}{c++} 191 | for (int* p = front; p < front + count; p++) /* Use *p */; 192 | \end{minted} 193 | Or more generally, with \texttt{c} being an instance of \texttt{Container}: 194 | \begin{minted}{c++} 195 | for (ptr p = c.begin(); p != c.end(); p = p.next() ) ... ; 196 | \end{minted} 197 | \end{frame} 198 | 199 | \begin{frame}{Performance of linear list} 200 | We assume a linear list with one end pointer. Here pointer refers to ``logical pointer", meaning any information that allows for obtaining the one-pass-the-end location in constant time. Note in the tables \textit{random access} refers to accessing through index. 201 | 202 | \vspace{-.2in} 203 | \begin{table} 204 | \begin{tabular}{l | c | l } 205 | Operation & Performance & Note \\ 206 | \hline \hline 207 | Insert at front & Super fast & Neglecting stretching\\ 208 | Deletion at front & Super fast+ & Update \texttt{size}\\ 209 | Insert at end & Reasonable & Move all elements\\ 210 | Deletion at end & Reasonable & Move all elements\\ 211 | Insert at middle & Reasonable & Move following elements\\ 212 | Deletion at middle & Reasonable & Move following elements\\ 213 | Random access & Super fast & Arrays are stored continuously\\ 214 | Forward iteration & Easy & iterate by index\\ 215 | Backward iteration & Easy & iterate by index\\ 216 | Memory consumption & Least & (Arguably, unused space) \\ 217 | \end{tabular} 218 | \end{table} 219 | \end{frame} 220 | 221 | \begin{frame}{Performance of Singly Linked list} 222 | We assume a singly linked list with both front and end pointer. 223 | 224 | \vspace{-.1in} 225 | \begin{table} 226 | \begin{tabular}{l | c | l } 227 | Operation & Performance & Note \\ 228 | \hline \hline 229 | Insert at front & Super fast & allocate a node\\ 230 | Deletion at front & Super fast & delete a node\\ 231 | Insert at end & Super fast & allocate a node\\ 232 | Deletion at end & \alert{Reasonable*} & Why?\\ 233 | Insert at middle & Super fast & play around pointers\\ 234 | Insert at middle & Super fast & play around pointers\\ 235 | Random access & \alert{Reasonable*} & Need to follow the links\\ 236 | Forward iteration & Easy & Use the link, Luke.\\ 237 | Backward iteration & \alert{Slow} & Why? \\ 238 | Memory consumption & \alert{A little} & 1 extra ptrs / elem\\ 239 | \end{tabular} 240 | \end{table} 241 | \end{frame} 242 | 243 | \begin{frame}{Performance of \alert{Doubly} Linked list} 244 | We assume a doubly linked list with both front and end pointer. 245 | 246 | \vspace{-.1in} 247 | \begin{table} 248 | \begin{tabular}{l | c | l } 249 | Operation & Performance & Note \\ 250 | \hline \hline 251 | Insert at front & Super fast & allocate a node\\ 252 | Deletion at front & Super fast & delete a node\\ 253 | Insert at end & Super fast & allocate a node\\ 254 | Deletion at end & \alert{Super fast} & Compare with previous\\ 255 | Insert at middle & Super fast & play around pointers\\ 256 | Insert at middle & Super fast & play around pointers\\ 257 | Random access & \alert{Reasonable*} & Could be improved.\\ 258 | Forward iteration & Easy & Use the link, Luke.\\ 259 | Backward iteration & \alert{Easy} & Thanks to the reverse link.\\ 260 | Memory consumption & A little* & 2 extra ptrs / elem \\ 261 | \end{tabular} 262 | \end{table} 263 | \end{frame} 264 | 265 | \begin{frame}{Implementation of Circular Array} 266 | \begin{small} 267 | A circular array is sequential data structure. It is based on an array. It uses both front and rear ptrs to indicate begin and end. When a new element is added into the array, front moves to begin and rear moves to end, both ptrs wrap around. 268 | \end{small} 269 | 270 | \vspace{-.15in} 271 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{36} 272 | %\bitheader[endianness=little]{0,4,8,12,16,20,24,28,32}\\ 273 | \begin{leftwordgroup}{} 274 | \bitbox[]{32}{} 275 | \bitbox[]{4}{\texttt{SIZE=8}\\ \texttt{count=4}} 276 | \end{leftwordgroup}\\ 277 | \begin{leftwordgroup}{data} 278 | \bitbox{4}{-1} 279 | \bitbox{4}{3} 280 | \bitbox{4}{8} 281 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 282 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 283 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 284 | \bitbox{4}{\color{lightgray}\rule{\width}{\height}} 285 | \bitbox{4}{-10} 286 | \bitbox[]{4}{} 287 | \end{leftwordgroup}\\ 288 | \begin{leftwordgroup}{} 289 | \bitbox[]{8}{} 290 | \bitbox[]{8}{\textuparrow\quad Rear}\bitbox[]{12}{} 291 | \bitbox[]{8}{\textuparrow\quad Front} 292 | \end{leftwordgroup}\\ 293 | \end{bytefield} 294 | 295 | \vspace{-.3in} 296 | \begin{center} 297 | \begin{tikzpicture}[>=latex,font=\sffamily,semithick,scale=1.75] 298 | \fill [green!25] (0,0) -- (135:1) arc [end angle=-45, start angle=135, radius=1] -- cycle; 299 | \draw [thick] (0,0) circle (1); 300 | \foreach \angle in {90,45,...,-45} 301 | \draw (\angle:1) -- (\angle-180:1); 302 | \node [circle,thick,fill=white,draw=black,align=center,minimum size=3cm] at (0,0) {}; 303 | \draw [<-] (125:1) -- (125:1.25) -- +(-.333,0) 304 | node [left,inner xsep=.333cm] (Head) {Rear (end)}; 305 | \draw [<-] (-33.75:1) -- (-33.75:1.25) -- +(.333,0) 306 | node [right,inner xsep=.333cm] (Tail) {Front};(Head.west); 307 | 308 | \path 309 | (15 :.7cm) node[]{0} 310 | (60 :.7cm) node[]{1} 311 | (105:.7cm) node[]{2} 312 | (150:.7cm) node[]{3} 313 | (195:.7cm) node[]{4} 314 | (240:.7cm) node[]{5} 315 | (285:.7cm) node[]{6} 316 | (330:.7cm) node[]{7}; 317 | \end{tikzpicture} 318 | \end{center} 319 | \end{frame} 320 | 321 | \begin{frame}{Performance of Circular Array} 322 | We assume a circular array with \textbf{fixed} size and both front and rear pointer. 323 | 324 | \vspace{-.1in} 325 | \begin{table} 326 | \begin{tabular}{l | c | l } 327 | Operation & Performance & Note \\ 328 | \hline \hline 329 | Insert at front & Super fast & \\ 330 | Deletion at front & Super fast & Move front ptr\\ 331 | Insert at end & Super fast & \\ 332 | Deletion at end & Super fast & Move rear ptr\\ 333 | Insert at middle & Reasonable & How?\\ 334 | Deletion at middle & Reasonable & How?\\ 335 | Random access & Super fast & How?\\ 336 | Forward iteration & Easy & \\ 337 | Backward iteration & Easy & \\ 338 | Memory consumption & Least & Unused space \\ 339 | \end{tabular} 340 | \end{table} 341 | \end{frame} 342 | 343 | \begin{frame}{A note on the performance} 344 | 345 | \end{frame} 346 | 347 | \subsection{Standard Template Library} 348 | \begin{frame}{History of the standard template library} 349 | 350 | \end{frame} 351 | 352 | \begin{frame}{\texttt{std::vector}} 353 | 354 | \end{frame} 355 | 356 | \begin{frame}{\texttt{std::list}} 357 | 358 | \end{frame} 359 | 360 | \begin{frame}{\texttt{std::map}} 361 | 362 | \end{frame} 363 | 364 | \begin{frame}{\texttt{std::unordered\_map}} 365 | 366 | \end{frame} -------------------------------------------------------------------------------- /week11.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 11} 2 | \subsection{Generics, polymorphism and templated containers} 3 | \begin{frame}{Preliminary: A container of pointer} 4 | As a kind reminder we briefly discuss containers of pointers here. The key idea in the whole discussion again is the problem of the ownership. 5 | 6 | One must be crystal clear that a container of pointer actually owns the object, which means: 7 | 8 | \begin{itemize} 9 | \item Pass to a container only things you have ownership. 10 | \item When you pop from a container, you must take over ownership. 11 | \item When an object has been passed to the container, it's the container's responsibility and authority to treat the object. You should not use the object in any way since you no longer owns the object. 12 | \end{itemize} 13 | 14 | With this in mind we take a look a few slides: 15 | 16 | \end{frame} 17 | 18 | \begin{frame} 19 | \includegraphics[scale=0.47]{fig/s1} 20 | \end{frame} 21 | 22 | \begin{frame} 23 | \includegraphics[scale=0.47]{fig/s2} 24 | \end{frame} 25 | 26 | \begin{frame}{Do not repeat your self} 27 | Containers are objects to contain other objects, they do not have an intrinsic meaning. From now on we focus on \alert{Containter of pointers} (though we use a container of value in this example). Consider the example of a container of \texttt{char} and \texttt{int}: 28 | 29 | \vspace{-0.1in} 30 | \begin{figure} 31 | \centering 32 | \includegraphics[scale=0.47]{fig/rc11dry} 33 | \end{figure} 34 | 35 | \end{frame} 36 | 37 | \begin{frame}{Generics and polymorphism} 38 | We would imagine they share the same implementation. Now our DRY principal suggest we should find a way to abstract out the almost identical implementation. 39 | 40 | Now we must familiar ourself to two widely used terms: 41 | 42 | \begin{description}[Polymorphism] 43 | \item[Generics] A generic algorithm is an algorithm that does not depend on a specific type. Type can be specified later. 44 | \item[Polymorphism] Polymorphism is a property of code. A piece of code is said to be polymorphic, if it works on ``a range of" types. 45 | \end{description} 46 | 47 | Clearly polymorphism is a technique to achieve generics. What we need to implement here is a generic algorithm (data structure), and we are going to use polymorphic code to achieve our purpose. 48 | \end{frame} 49 | 50 | \begin{frame}{Polymorphism tool box} 51 | We first start by examining our polymorphism toolbox. In general there are 3 ways achieve (different levels) of polymorphism. 52 | 53 | Polymorphic code always involve a time where the ``real" implementation starts to step in. In general there are two timings: 54 | \begin{description}[Compile-time] 55 | \item[Compile-time] The compiler ``injects" the real implementation into our polymorphic code when it is being compile. Sometimes called \textit{static polymorphism}. 56 | \item[Runtime] The polymorphic behavior is determined when it is needed at runtime. A typical example is \texttt{virtual} functions. It introduces overhead. 57 | \end{description} 58 | 59 | We now examine our choices: 60 | 61 | \begin{description}[Overloading] 62 | \item[Overloading] Function / operator overloading. Limited power. 63 | \item[Subtyping] Virtual functions. Polymorphism through dynamic dispatch. This is runtime polymorphism. 64 | \item[Parametric] Templates in C++. Type as a parameter. 65 | \end{description} 66 | \end{frame} 67 | 68 | \begin{frame}[fragile]{Polymorphic containers} 69 | Both of the second and third solution can be used to solve our problem at hand. We first look at the second one. We now introduces \texttt{Polymorphic containers}. 70 | 71 | In a polymorphic container, the basic idea is to create a universal super type. Every type it it's subtype. And a container is written in terms of the universal super type. 72 | 73 | The universal super type looks like the following: 74 | 75 | \begin{minted}{c++} 76 | struct Object { 77 | virtual ~Object() {} 78 | virtual Object* clone() = 0; 79 | } 80 | \end{minted} 81 | 82 | Every class to be pushed into the container should be a subtype of this class. There are two questions: why are both methods virtual? Why do we need the \texttt{clone()} method. 83 | \end{frame} 84 | 85 | \begin{frame}{Polymorphic containers} 86 | Note when we copy construct the constructor we also use copy copy constructor to copy the contained objects. 87 | 88 | \includegraphics[scale=0.4]{fig/rc11pc1} 89 | 90 | But unfortunately this simply cannot work. Remember that constructors cannot be virtual, since it is not possible for a base class object to setup invariants for a derived class object. 91 | 92 | Note above code does compile (why?). However what we get from such construction is an empty, useless \texttt{Object} class instance. 93 | \end{frame} 94 | 95 | \begin{frame}[fragile]{Polymorphic containers: copying} 96 | \small 97 | The solution is to ask the derived class instance to make a copy itself. This gives us the \texttt{clone()} method in the previous slides. This methods asks the object to make a copy of itself and returns a ptr to base class. 98 | 99 | Now our copy method can be written as follows: 100 | 101 | \begin{minted}{c++} 102 | void List::copyList(node *list){ 103 | if (list != NULL) { 104 | Object *o; copyList(list->next); 105 | o = list->value->clone(); insert(o); } } 106 | \end{minted} 107 | 108 | Note this design makes sense from an interface point of view. In order for an object to be put inside a container it must be copyable. For normal container this is checked by the compile for the copy constructor (since the compiler knows the type in question). For polymorphic container since the compiler do not know what type is contained in advance so we must specify the constraint by ourself, namely through adding a \texttt{clone()} method. 109 | \end{frame} 110 | 111 | \begin{frame}[fragile]{Type Erasure} 112 | We would like to make a final note. Consider when you pop something out of the container. The container only knows that the value is of type \texttt{Object*}. But you know it is actually an instance of \texttt{Derived*}. And most likely you need to use it as a \texttt{Derived} object. You need to transform a base class pointer to a derived class pointer. 113 | 114 | \vspace{0.1in} 115 | 116 | This way you will need a cast: 117 | \begin{minted}{c++} 118 | Derived* bp = dynamic_cast(list.remove()); 119 | \end{minted} 120 | The \texttt{dynamic\_cast<>} checks at \alert{runtime} if the pointer of base class is actually a pointer of derived class. If not so it returns \texttt{nullptr}. 121 | \end{frame} 122 | 123 | \begin{frame}{Type Erasure} 124 | Note all this must happen at run-time. No checks will be done at compile time. This has both up-side and down-side: 125 | \begin{itemize} 126 | \item Since actual type is involved only when used this allows for heterogeneous containers. The contained object does not have to of the same type. This is a huge gain. 127 | \item However the cost is also significant! Since all checks are done at runtime, there is not type check at compile time either. Type mismatch will be deferred to runtime. This makes writing type safe code much harder! 128 | \end{itemize} 129 | Since essentially we are ``erasing" the actual type information of the objects when we put them into the container, this strategy is often called \textit{type erasure}. 130 | 131 | Problematic as it seems, \texttt{JAVA} choses to use type erasure when it comes to generics. This is one of the debatable feature of the language. 132 | \end{frame} 133 | 134 | \begin{frame}{Poor man's template C++} 135 | Now we turn to \texttt{template}, which is so called \textit{parametric polymorphism}. Before we introduce that in C++, I would like to familiarize you with a piece of code in C++: 136 | \inputminted[]{c++}{code/rc11cp/poly.cpp} 137 | \end{frame} 138 | 139 | \begin{frame}[fragile]{Poor man's template in C++} 140 | The code seems very cryptic at first. We now look at what it does by expanding the macros. \texttt{SWAP(int)} would be expanded into \texttt{swap\_int}. The two sharp signs means concatenating. An \texttt{SWAP\_IMPL(swap)} will be expanded into. 141 | \begin{minted}{c++} 142 | static void swap_int (int &x, int &y) { 143 | int t = x; x = y; y = x; 144 | } 145 | \end{minted} 146 | This is a very straight forward swapping two integers. As you can see this way we can reuse the \texttt{swap} function easily for different types by simpling use \texttt{SWAP\_IMPL} to create an implementation for different types and call them with \texttt{SWAP()}. 147 | 148 | Further more we can put the two macro definitions into a header file and include the when we need to. 149 | \end{frame} 150 | 151 | \begin{frame}{Templates} 152 | A template in C++ does exactly the same (for now. It if far more complicated if you explore deeper). When you write a template, for example: 153 | \begin{columns} 154 | \column[]{.4\textwidth} 155 | 156 | \includegraphics[scale=0.4]{fig/rc11pc3} 157 | 158 | \column[]{.6\textwidth} 159 | \vspace{-.3in} 160 | \begin{itemize} 161 | \small 162 | \item \texttt{T} is called a template parameter. It is usually a \texttt{class}, but it can be a value (e.g. an \texttt{int}). 163 | \item The traditional way of specifying the type parameter is through \texttt{template}. But after C++11 one could use \texttt{template}. 164 | \item A template is much like a macro. When it comes to using it, the compiler uses an actual type to replace the type argument, and generate a version of implement for that type. 165 | \end{itemize} 166 | \end{columns} 167 | \end{frame} 168 | 169 | \begin{frame}[fragile]{Template instantiation} 170 | When you use a templated class, for example: 171 | \begin{minted}{c++} 172 | List intList; 173 | \end{minted} 174 | The compiler will automatically produce a version of the actual code with the \texttt{int} as the parameter. This process is called \textit{template instantiation}. Template instantiation is conceptually the compiler writing \texttt{SWAP\_IMPL(int)} for us. 175 | 176 | We would like to make a footnote here. A template is by no means a type. A template is not a type since you cannot have a variable of \texttt{List} type clearly. It can be \texttt{List} or \texttt{List}, but simply is not \texttt{List}. A template is incomplete. It becomes a type when you put an actual type argument into it. 177 | 178 | In some literature templates are refered as a \textit{dependent type}. 179 | You should notice this behavior is very much like a \textit{function}, which takes in a type and spits out another type. This function is ``sort of" evaluated in \alert{compile type}. 180 | \end{frame} 181 | 182 | \begin{frame}[fragile]{A comment on the syntax} 183 | Templates and \alert{their implementation} is almost always written in a header file (I would say always if not for the project). Libraries consists only of template classes are often called header libraries. The reason behind this should be simple from the previous poor-man's template example. 184 | 185 | There are in general two ways of implementing a templated class method. 186 | \begin{itemize} 187 | \item You can implement it inside the declaration. 188 | \item You can implement separately. 189 | \end{itemize} 190 | For the second method: 191 | \begin{minted}{c++} 192 | template void List::isEmpty() {...} 193 | \end{minted} 194 | \alert{The beginning \texttt{templated } must be there}. Note the method is implemented \alert{within the namespace \texttt{List}}. This makes sense since namespaces corresponds to types, and \texttt{List} is a type, \texttt{List} is not. 195 | \end{frame} 196 | 197 | \begin{frame}[fragile]{A comment on the syntax} 198 | We would like to make a comment on the following slide (ch21,30): 199 | \includegraphics[scale=0.4]{fig/rc11p4} 200 | \end{frame} 201 | 202 | \begin{frame}[fragile]{A comment on the syntax} 203 | We would like to make a comment on the following slide (ch21,30): 204 | 205 | \vspace{0.1in} 206 | \includegraphics[scale=0.4]{fig/rc11p4} 207 | \end{frame} 208 | 209 | \begin{frame}[fragile]{A comment on the syntax} 210 | You should find this to be very weired. Take a look at 211 | \begin{minted}{c++} 212 | List& List::operator=(const List &l); 213 | \end{minted} 214 | Now what is the type of \texttt{l}? We have commented that \texttt{List} does not name a type. But clearly \texttt{l} is function argument and it must have a type. The professor commented ``No \texttt{}!". 215 | 216 | After a little research this is called a injected-class-name. Basically if you write \texttt{List} is a templated class, it will be inferred as \texttt{List}, so we could use \texttt{List} as a shorthand of \texttt{List} inside class declaration. We would like to note: 217 | \begin{itemize} 218 | \item It is syntactically correct to write \texttt{List}. 219 | \item It is also the recommended way as long as it does not impact readability too much, since it enhances clarity and makes more sense. 220 | \end{itemize} 221 | \alert{Note the name of the ctor/dtor must be \texttt{List}, not \texttt{List}}. 222 | \end{frame} 223 | 224 | \begin{frame}[fragile]{A comment on the syntax} 225 | We would like to emphasize on one thing, consider the following code 226 | \begin{minted}{c++} 227 | // Create a static list of integers 228 | List li; 229 | // Create a dynamic list of integers 230 | List *lip = new List; 231 | // Create a dynamic list of doubles. 232 | List *ldp = new List; 233 | \end{minted} 234 | Essentially forms \texttt{List} are no difference to a regular \texttt{int}, \texttt{IntSet} etc. Anywhere a type can be use, such form can be use. For example it is possible to inherit from a templated type: 235 | \begin{minted}{c++} 236 | class Foo : public: List {...} 237 | \end{minted} 238 | And then override some of its methods. 239 | \end{frame} 240 | 241 | \begin{frame}{Compile time polymorphism trade-offs} 242 | \small 243 | Now we are at the core of compile time polymorphism. Templates are instantiated at compile time. The instantiation process is essentially the compiler deciding when to plug in the actual implementation. This gives us the following trade-offs: 244 | \begin{itemize} 245 | \item It enhance code safety, by a lot. After substituting the type parameter with the actual type the compiler will be able to perform type checks. Type mismatches will be caught so that code correctness is improved. 246 | \item It improves performance (compared to polymorphic containers). Since the dispatch is done at compile time there is no run-time overhead. Compile-time dispatch also allows for further (much more) optimizations. 247 | \end{itemize} 248 | 249 | Above two are the major reasons people use templates. This is also why standard libraries choose to use templates to implement generic containers, since C++ is a language that focuses on performance and static typing. 250 | \end{frame} 251 | 252 | \begin{frame}{Compile time polymorphism trade-offs} 253 | \small 254 | Now we take a look at the down sides 255 | \begin{itemize} 256 | \item It prolongs compile time (a lot). The template system of C++ is so powerful that it self is Turing complete: meaning it is possible to write algorithms in terms of templates, or infinite loops that crashes the compiler. 257 | \item It increases the executable size. Each template instantiation creates more code. This gets worse combined with the C++'s ``one file per object" rule, as we will see next. 258 | \end{itemize} 259 | 260 | The first point is not really a pure down side. Some people heavily exploit the first point and ends up creating a whole new area of programming, called \textit{meta-programming}. 261 | 262 | The second down side is generally OK for most desktop applications since people have large memories. But for embedded applications where memories are scares, this basically rules STLs out from the embedded use. 263 | 264 | Another problem with templates is it complicates the compiler by a lot. However it is not a bad news for you. 265 | \end{frame} 266 | 267 | \begin{frame}[fragile]{Operator overloading} 268 | We now fill in the final piece of puzzle, i.e. operator overloading. We have introduced this in the previous slides. See page 253/254. 269 | 270 | Again just as a reminder there are two ways to write an overloaded operator: 271 | \begin{itemize} 272 | \item As a class method of the first operand (if there are multiple operands) 273 | \item Write as a normal method. 274 | \end{itemize} 275 | 276 | The second approach is very common for overloading the extraction / push operator on a I/O stream (pay attention to the return type of the function). For example: 277 | 278 | \begin{minted}{c++} 279 | ostream& operator<< (ostream &s, const MyClass &r) {...} 280 | \end{minted} 281 | 282 | allows you to print to \texttt{cout} and \texttt{fstream} (why?) by: 283 | \begin{minted}{c++} 284 | Ofstream file(...); MyClass obj(...); 285 | file << obj; cout << obj; 286 | \end{minted} 287 | 288 | \end{frame} 289 | 290 | \begin{frame}[fragile]{\texttt{friend} keyword} 291 | \small 292 | In our previous example \texttt{operator<<} might need to access private member of \texttt{MyClass} instance. You could provide an accessing operator for each of the member, but often it is not a good idea (why?). 293 | 294 | One workaround is specifically grant \texttt{operator<<(ostream \&s, const MyClass \&r)} access to the protected members. This can be done by using the \texttt{friend} keyword: 295 | 296 | \begin{minted}{c++} 297 | class MyClass { 298 | friend ostream& operator<< (ostream &s, const MyClass &r);} 299 | \end{minted} 300 | 301 | It doesn't matter where this is marked \texttt{public} or \texttt{private}. Note \texttt{friend} can also grant access to regular functions and even classes: 302 | 303 | \begin{minted}{c++} 304 | class MyClass { 305 | friend class Bar; friend int foo(double foo);} 306 | \end{minted} 307 | 308 | Pay attention that \texttt{friend} is not mutual. If \texttt{ClassA} declares \texttt{ClassB} as \texttt{friend}. \texttt{ClassB} can access \texttt{ClassA}'s private member, but the other way around doesn't work. 309 | \end{frame} -------------------------------------------------------------------------------- /week8.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 8} 2 | 3 | \subsection{Working with class invariants} 4 | \begin{frame}{Invariants of a datatype} 5 | We now take a look at the implementation side. From a implementation point of view, what's the difference between a list of integers, and a set of integers? 6 | \begin{itemize} 7 | \item Both of them probably are represented using an array. 8 | \item Both of them might need to keep track of current number of elements. 9 | \end{itemize} 10 | The major difference lies in the fact that when inserting an element, integer set must check whether the element already exists. It is the assumptions on the member that makes them different. 11 | 12 | \vspace{0.05in} 13 | Integer set has one more assumption than integer list. Each number in the array must be unique. Every operation of an integer set must start with this assumption, might broke it in the middle, but ends up with it. 14 | 15 | \vspace{0.05in} 16 | We will use your \texttt{IntSet} example in class for our discussion. 17 | \end{frame} 18 | 19 | \begin{frame}{Example of invariants} 20 | \begin{columns} 21 | \column[]{.5\textwidth} 22 | 23 | \vspace{-.3in} 24 | \inputminted[fontsize=\small]{c++}{code/rc8intset/intset.h} 25 | 26 | Invariants: 27 | 28 | 1) Numbers are arranged in \texttt{elts} sequentially from index zero. 29 | 30 | 2) Number of elements in array equals to the value of \texttt{numElts}. 31 | 32 | 3) Numbers are unique. 33 | \column[]{.6\textwidth} 34 | 35 | \vspace{-.25in} 36 | Guideline is: 37 | \begin{itemize} 38 | \item Methods assume inv.s on entry. 39 | \item (Public) Methods must preserve inv.s on the moment of exit. 40 | \item Nobody cares what happens in the middle! 41 | \end{itemize} 42 | This way we safely claim invariants are always preserved for an class instance from an external point of view. 43 | 44 | Analyze the methods: 45 | \begin{itemize} 46 | \item \texttt{insert} might broke all three. 47 | \item \texttt{remove} might broke 1) and 2). 48 | \item \texttt{const} methods will not break anything! One more advantage! 49 | \end{itemize} 50 | \end{columns} 51 | \end{frame} 52 | 53 | \begin{frame}{Example of invariants: Implementing methods} 54 | \begin{columns} 55 | \column[]{.5\textwidth} 56 | 57 | \vspace{-.3in} 58 | 59 | \inputminted[fontsize=\small,xleftmargin=1em, linenos]{c++}{code/rc8intset/intset.cpp} 60 | 61 | \column[]{.6\textwidth} 62 | 63 | \vspace{-.25in} 64 | 65 | Analyze the methods: 66 | \begin{itemize} 67 | \item L.9 checks inv.3 for uniqueness. 68 | \item L.7 checks inv.2 for capacity. If violation of inv cannot be recovered from, depending on how serious situation is you can \texttt{throw} or fail-fast. 69 | \item L.9 uses inv.1. We insert at the end, temporarily breaks invariance. 70 | \item L.9 operator \texttt{++} restores inv. 71 | \item Inv.3 ensures \texttt{remove} works. 72 | \item L.15 restores inv.1. L.16 restores inv.2. A significant amount of code is dedicated to preserving invs. 73 | \end{itemize} 74 | \end{columns} 75 | \end{frame} 76 | 77 | 78 | \begin{frame}{Remarks on invariants} 79 | We would like to note the following things: 80 | \begin{center} 81 | \structure{The centric problem in choosing an implementation\\ for an ADT, is choosing the invariants.} 82 | \end{center} 83 | There are multiple ways to write an implementation an \texttt{IntSet} of course. The major difference of them, is they need to keep different invariants, and thus have different performance. 84 | 85 | For example, you have already seen \texttt{IntSet} implemented using a sorted array. The one extra invariant you need to keep is that elements are sorted. Based on that extra invariant: 86 | \begin{itemize} 87 | \item Queries are much quicker. 88 | \item Deletion and insertion are slower (by a constant factor). 89 | \end{itemize} 90 | In VE281 you will see (many) other ways of implementing this IntSet, for example using hash tables, or balance trees. It is always helpful to understand what the invariant for an implementation. 91 | \end{frame} 92 | 93 | \begin{frame}{Invariants and bad practices} 94 | Thinking about invariants immediately gives us hints on what are seemingly good, some even sounds terrific, but are actually pretty bad ideas. We now take a look at some of them. 95 | 96 | \begin{description}[Alice] 97 | \small 98 | \item[Alice] I'd like to add a public method to \texttt{IntSet}, let's say \texttt{find()}, which takes an element, found it in the set, and returns an reference to that element. 99 | \item [Bob] Why do you want to do that? 100 | \item [Alice] Well my code needs to modify elements in the array, a lot. This would significantly accelerate the process. 101 | \item [Bob] ... 102 | \item [Alice] Oh, I get it, it's a pretty bad idea. OK I have another idea, I want to add a method, \texttt{data()}, which returns the pointer to array, since my code needs to iterate through the set. 103 | \item [Bob] ... 104 | \item [Alice] What if I return pointer to const? 105 | \item [Bob] ... 106 | \item [Alice] Well, I give up. It's not as easy as I thought. 107 | \end{description} 108 | \end{frame} 109 | 110 | \begin{frame}{Invariants and bad practices} 111 | Well Alice does have her point. Her requirements are very real and the solutions does solutions could work, but remember the words from \textit{Donald Knuth}: 112 | \begin{quotation} 113 | \structure{Premature optimization is the root of all evil}. 114 | \end{quotation} 115 | Never trade correctness for performance in designing phase. 116 | \begin{itemize} 117 | \small 118 | \item 1st and 2nd change Alice proposed have the problem that the client could change the content of the internal array, without notifying the instance. There is by no means the instance can guarantee the new value won't violate uniqueness invariance. 119 | \item Now Alice proposes the third one. The \texttt{const} key word could prevent the element from being modified. But it exposes the implementation to outside. Now the fact that elements are stored in a linear array becomes part of the abstraction, you can no longer change that. The problem is, iterating through a set seems to be an important feature, we DO need that. Well, the correct solution is using iterators, you will know them later in this course. 120 | \end{itemize} 121 | \end{frame} 122 | 123 | \begin{frame}{Invariants and bad practices} 124 | Well Alice does have her point. Her requirements are very real and the solutions does solutions could work, but remember the words from \textit{Donald Knuth}: 125 | \begin{quotation} 126 | \structure{Premature optimization is the root of all evil}. 127 | \end{quotation} 128 | Never trade correctness for performance in designing phase. 129 | \begin{itemize} 130 | \small 131 | \item 1st and 2nd change Alice proposed have the problem that the client could change the content of the internal array, without notifying the instance. There is by no means the instance can guarantee the new value won't violate uniqueness invariance. 132 | \item Now Alice proposes the third one. The \texttt{const} key word could prevent the element from being modified. But it exposes the implementation to outside. Now the fact that elements are stored in a linear array becomes part of the abstraction, you can no longer change that. The problem is, iterating through a set seems to be an important feature, we DO need that. Well, the correct solution is using iterators, you will know them later in this course. 133 | \end{itemize} 134 | \end{frame} 135 | 136 | \begin{frame}{Invariants and the constructor} 137 | \alert{Invariants are there as long as the object is there.} The earliest moment the object is created, is when it is defined. Classes, are just structures, in terms of memory. Structures contains undefined values when created, so naturally does the classes. 138 | 139 | \vspace{0.03in} 140 | Think about \texttt{IntSet}, when the object is created, chances are \texttt{numElts} contains non-zero value, while your set should be empty. 141 | 142 | \vspace{0.03in} 143 | We need a mechanism, a function, that is invoked whenever the an instance is created. This function is called, and called always, to initialize the object, or more strictly, to setup the invariance. 144 | 145 | \vspace{0.03in} 146 | Such special functions are \alert{constructors}, or \alert{ctors} for short. From this point on it's important to think the initialization, not as assigning special values to member variables, but as invoking the constructor to setup invariants (together with the initial state, e.g. initialize the \texttt{IntSet} with one default element in it for whatever reason). 147 | \end{frame} 148 | 149 | \begin{frame}[fragile]{Constructors: Syntax} 150 | 151 | \begin{columns} 152 | \column[]{.5\textwidth} 153 | 154 | \vspace{-.3in} 155 | The construct for \texttt{IntSet}: 156 | \inputminted[]{c++}{code/rc8intset/intset_ctor.h} 157 | 158 | 159 | \column[]{.6\textwidth} 160 | 161 | \vspace{-.65in} 162 | 163 | \begin{itemize} 164 | \small 165 | \item Ctors have same name as class. 166 | \item Ctors don't return anything. 167 | \item Usually \texttt{public}, but could be \texttt{private} for special need. 168 | \item A class could have more than one ctor, depending on what the initial state should be. We say the constructor is overloaded. 169 | \item Ctors could take initialization list. 170 | \item Ctor is the first function being called when the object is created. Unfortunately ``created" is not as simple as it sounds. 171 | \item A ctor that does not take argument is called \texttt{a default ctor}. Every class must always have a ctor. If you don't specify \alert{any ctor}, a ctor is synthesized for you (under some conditions). 172 | \end{itemize} 173 | \end{columns} 174 | \tiny{* We left out copy/move constructors on purpose. You will learn them later.} 175 | \end{frame} 176 | 177 | \begin{frame}[fragile]{Constructors: Explanations} 178 | We need to break down the words from previous slide. We first look at the first four lines. The first three seems direct. For the fourth one: 179 | \begin{minted}{c++} 180 | IntSet set1; // set1 is init to an empty set; 181 | IntSet set2(10); // set2 contains single elem 10 182 | \end{minted} 183 | 184 | \begin{minted}{c++} 185 | int foo(const IntSet& s1, const IntSet& s2); 186 | foo(IntSet(), IntSet(10)); // Anymous construction 187 | \end{minted} 188 | 189 | Further more, latest C++ standard guarantees the following: 190 | \begin{minted}{c++} 191 | IntSet setx = IntSet(); // Same as set1 192 | IntSet sety = IntSet(10); // Same as set2 193 | IntSet setz = 10; // Same as set2 194 | \end{minted} 195 | This is non-trivial, for reasons you will see one or two weeks later. This is called \textit{guaranteed copy elision}. Now some food for thought: 196 | 197 | Why \texttt{set1} is not initialized as \texttt{IntSet set1();} for consistency? 198 | \end{frame} 199 | 200 | \begin{frame}[fragile]{Constructors: Explanations} 201 | We now question: Is constructor really the first function being called when created? Well that depends on how you understand ``created"! One should argue the ctor IS part of object creation. 202 | 203 | \vspace{0.1in} 204 | In fact, there are 4 steps (roughly) in creating an class instance. 205 | \begin{enumerate} 206 | \item Allocation of space, we (in general) don't have control over. 207 | \item Construction of the base class object. 208 | \item Construction of the members of current class. 209 | \item Calling the constructor. 210 | \end{enumerate} 211 | These 4 steps goes recursively. In fact the constructor is the last function being called. This is natural. 212 | 213 | When the constructor is called, we should be able to use all member variables and base class. So their invariants must have been setup in advance! This is the only way things makes sense. 214 | \end{frame} 215 | 216 | \begin{frame}[fragile]{Initializer list: Setup} 217 | The \textit{initializer list}, the things after colon controls the second and third step. 218 | 219 | \begin{minted}{c++} 220 | ClsName::ClsName() : base(..), m1(..), m2(..) { 221 | // Code for the constructor goes here 222 | } 223 | \end{minted} 224 | 225 | %You might wonder, wait a minute, I have never write initializer list before, I don't even write a constructor! 226 | 227 | To better illustrate our ideas, we make some changes to our original \texttt{IntSet}, specifically 2 changes: 228 | 229 | \begin{itemize} 230 | \item We add a line of output to the ctors to indicate with constructor is being called. 231 | \item We make 2 more ``version" of our original \texttt{IntSet}, one \texttt{OddIntSet} and \texttt{EvenIntSet}. They only allow odd and even numbers, respectively. 232 | \end{itemize} 233 | 234 | We now propose a slightly faster \texttt{IntSet}. This \texttt{IntSet} is composed of an \texttt{OddIntSet} and \texttt{EvenIntSet}. It dispatches the operation on integers to those two sub-\texttt{IntSet}. 235 | % 236 | %Well, if you don't provide any initializer list, the compiler calls the default constructor on every ctor, if a default ctor is available. If the default ctor is not available, a compile error is thrown. 237 | \end{frame} 238 | 239 | \begin{frame}[fragile]{Initializer list: Setup} 240 | The \textit{initializer list}, the things after colon controls the second and third step. 241 | 242 | \begin{minted}{c++} 243 | ClsName::ClsName() : base(..), m1(..), m2(..) { 244 | // Code for the constructor goes here 245 | } 246 | \end{minted} 247 | 248 | 249 | 250 | To better illustrate our ideas, we make some changes to our original \texttt{IntSet}, specifically 2 changes: 251 | 252 | \begin{itemize} 253 | \item We add a line of output to the ctors to indicate with constructor is being called. 254 | \item We make 2 more ``version" of our original \texttt{IntSet}, one \texttt{OddIntSet} and \texttt{EvenIntSet}. They only allow odd and even numbers, respectively. 255 | \end{itemize} 256 | 257 | We now propose a slightly faster \texttt{IntSet}. This \texttt{IntSet} is composed of an \texttt{OddIntSet} and \texttt{EvenIntSet}. It dispatches the operation on integers to those two sub-\texttt{IntSet}. 258 | % 259 | 260 | \end{frame} 261 | 262 | \begin{frame}[fragile]{Initializer list: Setup II} 263 | \begin{columns} 264 | \column[]{.5\textwidth} 265 | 266 | \vspace{-.3in} 267 | Decl. of \texttt{OddIntSet} 268 | \inputminted[fontsize=\small]{c++}{code/rc8init/oddintset.h} 269 | 270 | \column[]{.5\textwidth} 271 | 272 | \vspace{-.3in} 273 | Partial implementation: 274 | \inputminted[fontsize=\small]{c++}{code/rc8init/oddintset.cpp} 275 | \end{columns} 276 | 277 | We omit the very similar version for \texttt{EvenIntSet}. 278 | \end{frame} 279 | 280 | \begin{frame}[fragile]{Initializer list: Setup III} 281 | \begin{columns} 282 | \column[]{.5\textwidth} 283 | 284 | \vspace{-.2in} 285 | Declaration of \texttt{OddIntSet} 286 | \inputminted[fontsize=\small]{c++}{code/rc8init/fastintset.h} 287 | 288 | \column[]{.5\textwidth} 289 | 290 | \vspace{-.2in} 291 | Partial implementation: 292 | \inputminted[fontsize=\small]{c++}{code/rc8init/fastintset.cpp} 293 | \end{columns} 294 | 295 | \end{frame} 296 | 297 | \begin{frame}[fragile]{Initializer list: Example} 298 | We create a main function and instantiate an instance of \texttt{FastIntSet}. We observe the following ouput: 299 | \begin{minted}{text} 300 | OddIntSet dft ctor 301 | EvenIntSet elt ctor 302 | fIntSet ctor 303 | \end{minted} 304 | This implies an initialization order of \texttt{oddSet-evenSet-ctor}. This follows from our expectation. 305 | 306 | \vspace{0.1in} 307 | A (not so important) remark we would like to make is 308 | \begin{itemize} 309 | \item The order of initialization of the members is guaranteed by standard. It's NOT a UB! 310 | \item Contrary to intuition \textit{it is not specified by initializer list}, but by the order they appear in the declaration. 311 | \item Base objects are guaranteed to be initialized before members. 312 | \item We recommend you to specify the init-list in the same order as the declaration, for clearance. 313 | \end{itemize} 314 | \end{frame} 315 | 316 | \begin{frame}[fragile]{Initializer list: Default initialization} 317 | We now make a tiny change to the original setup. We change the ctor for \texttt{FastIntSet} to 318 | \begin{minted}{c++} 319 | FastIntSet::FastIntSet() 320 | : oddSet() {cout << "fIntSet ctor\n";} 321 | \end{minted} 322 | 323 | Oops, we forgot to specify initializer for \texttt{evenSet}. 324 | 325 | \begin{minted}{text} 326 | OddIntSet dft ctor 327 | EvenIntSet dft ctor 328 | fIntSet ctor 329 | \end{minted} 330 | 331 | \texttt{evenSet} is still initialized, no surprise, otherwise the invariant for \texttt{oddSet} would be broken. Members are default constructed, if they don't appear in the initializer list. We could even simply write 332 | 333 | \begin{minted}{c++} 334 | FastIntSet::FastIntSet() {cout << "fIntSet ctor\n";} 335 | \end{minted} 336 | 337 | Which will produce the same result. Now what about members like \texttt{int}? Well, you can think of them as a class, whose default constructor does nothing at all! 338 | \end{frame} 339 | 340 | \begin{frame}[fragile]{Initializer list: Default initialization} 341 | We can even leave out the constructor for \texttt{FastIntSet} entirely. In which case we would have the following output. 342 | 343 | \begin{minted}{text} 344 | OddIntSet dft ctor 345 | EvenIntSet dft ctor 346 | \end{minted} 347 | 348 | Essentially the compiler would synthesize (create) and constructor for you, whose initializer list initializes everything using their default constructor. 349 | 350 | You might wonder, wait a minute, I have never write initializer list before, I don't even write a constructor before this lesson! That's how you ``get away" with writing constructors before! 351 | 352 | Modern design principal is against leaving things unspoken. If you believe you only need a default constructor, you could do: 353 | 354 | \begin{minted}{c++} 355 | IntSet::InSet() = default; // In class decl. 356 | \end{minted} 357 | 358 | Next up we will look at something that is not taught in class, but problems you will meet in your own struggle with C++. 359 | \end{frame} 360 | 361 | \begin{frame}[fragile]{Initializer list: Default initialization} 362 | We first change the ctor of \texttt{FastIntSet} to 363 | \begin{minted}{c++} 364 | FastIntSet::FastIntSet() 365 | : oddSet() {cout << "fIntSet ctor\n";} 366 | \end{minted} 367 | 368 | Then we \textbf{remove the default ctor} for \texttt{EvenIntSet}. 369 | 370 | We compile the program. The question is what SHOULD happen? 371 | 372 | \pause 373 | \vspace{0.1in} 374 | From a design point of view, if a class does not provide a default constructor, indicates the class is not (more likely should not be) default constructible, there is no way to setup a invariance without supplying an argument. Think about it, what should be the default skin color for an instance of a human class? None. 375 | 376 | In this case, any reasonable design would require an compile error is thrown. This is exactly the case. They compiler will look for \texttt{evenIntSet::evenIntSet()} and reports a not-found error. \alert{Situation is similar if you leave out the entire ctor of \texttt{FastIntSet}.} 377 | \end{frame} 378 | 379 | \begin{frame}{Why initializing in initialization list is better?} 380 | You are asked this question in the lecture slides but the question is left unanswered in the lecture slides. 381 | 382 | \vspace{0.1in} 383 | Frankly the questions really should be the other way around: on what grounds do initialization in the code is better? I can think of the following reasons you should prefer (in some cases you have to use) initialization list: 384 | \begin{itemize} 385 | \item Performance. This will be discussed later on. In some cases the performance could be significant. 386 | \item Exception safety. We will discuss this when we you learn the rule of big three (five, actually). 387 | \item A member that don't have a default constructor must be initialized in the initialization list. 388 | \item \texttt{const} members and references can only be initialized in the initialization list. 389 | \item Semantic reasons. 390 | \end{itemize} 391 | \end{frame} 392 | 393 | \begin{frame}[fragile]{Comments on the performance argument} 394 | A final comment on the performance argument. Suppose we write 395 | \begin{minted}{c++} 396 | FastIntSet::FastIntSet() { 397 | cout << "fIntSet ctor\n"; 398 | oddSet = OddIntSet(); evenSet = eventSet(10); 399 | } 400 | \end{minted} 401 | You will observer 5 lines of output: 402 | \begin{minted}[fontsize=\small]{text} 403 | OddIntSet dft ctor // EvenIntSet dft ctor // 404 | fIntSet ctor // OddIntSet dft ctor // EvenIntSet elt ctor // 405 | \end{minted} 406 | Things that actually happened (with significant cost) are : 407 | \begin{itemize} 408 | \item Your member variables are first default constructed. 409 | \item Calls your constructor. 410 | \item You create 2 temporal objects, by default construction. 411 | \item You invoke an assignment operator and uses your temporal object to overwrite the member variables. 412 | \end{itemize} 413 | 414 | \end{frame} -------------------------------------------------------------------------------- /week6.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 6} 2 | 3 | \subsection{Engineering correctness: Testing} 4 | \begin{frame}{The definitive correctness myth} 5 | We quote the following words from one of yours (@LukeXuan) 6 | \begin{quotation} 7 | While testing did indeed help your code to behave correctly in most cases. It never gives full assurance. I think you should recommend the technology of formal methods, especially verification, to introduce the possibility of complete correctness of program to students. 8 | \end{quotation} 9 | Despite the obvious taunt in the words, these comment DOES speaks some, truth, that is: 10 | \begin{center} 11 | \structure{It is fundamentally impossible, proved in theory, to guarantee the absolute \textit{correctness} of the program by simply testing it.} 12 | \end{center} 13 | After all testing is an attempt to engineer correctness. It is an engineer method that aims at decreasing chances of software malfunction in the field, i.e. reliability. 14 | \end{frame} 15 | 16 | \begin{frame}{Two general strategies in testing} 17 | \begin{block}{Black box testing} 18 | Treat your program under testing as a ``blackbox". The tester cares only about input and output. Essentially our OJ does black-box testing. 19 | \end{block} 20 | \begin{block}{Glass box testing} 21 | Tester designs the test case according to the case. Test-cases are designed in such way that attempts to 22 | \begin{itemize} 23 | \item Achieve full coverage (Activate every branch once). 24 | \item Touch boundaries, base cases, or data-type boundaries. 25 | \item Stress the implementation, or exploit it for security reasons. 26 | \end{itemize} 27 | \end{block} 28 | \alert{Testing is always an active activity}, even for black box testing. Test cases are always designed with the technicals in heart. 29 | \end{frame} 30 | 31 | 32 | \begin{frame}{Input Partitioning} 33 | The purpose of the testing, in most common cases, is to reveal possible defects, be trying to pick representative inputs. 34 | 35 | The basic logic in designing test-cases is 36 | \begin{center} 37 | \structure{If this program works on X, so it should work on Y.} 38 | \end{center} 39 | 40 | The job of the tester is often to categorize all possible inputs into different \textit{equivalent classes} (if you still remember that term from VE203). For each equivalent class we pick a few inputs and assume if the function works for those input, it should work for all inputs within that class. 41 | 42 | \vspace{0.1in} 43 | Remember, again, \alert{testing is an creative process} that relies on your understanding of both the problem and implementation at hand. 44 | 45 | \vspace{0.1in} 46 | It is never an easy job to partition the input right. 47 | \end{frame} 48 | 49 | \begin{frame}[fragile]{Program under testing} 50 | The following program takes a string (of less than 100 characters) and decides whether it is palindromic recursively: 51 | \begin{minted}{c++} 52 | bool isPalindrome(const char* str, int size) { 53 | if (size == 0) return true; 54 | if (size == 1) return true; 55 | if (str[0] != str[size - 1]) return false; 56 | return isPalindrome(++str, size - 2); 57 | } 58 | int main() { 59 | char str[100]; cin >> str; 60 | int size = strlen(str); 61 | cout << isPalindrome(str, size); 62 | } 63 | \end{minted} 64 | \end{frame} 65 | 66 | \begin{frame}{Test Cases Designing: ``Normal Input"} 67 | The most common kind of test cases are ``Normal Inputs". Normal inputs are considered normal in the following sense: 68 | \begin{itemize} 69 | \item They are normal in range. 70 | \item They are normally constructed, i.e. are not delicated constructed to sabatotage / overload the program. 71 | \item They cover most normal outputs. 72 | \end{itemize} 73 | For our previous example some good test cases will be: 74 | \begin{itemize} 75 | \item \texttt{"12321"} Odd size palindrome 76 | \item \texttt{"1221"} Even size palindrome 77 | \item \texttt{"1222"} Even size non-palindrome 78 | \item \texttt{"1234345"} Odd size non-palindrome 79 | \end{itemize} 80 | \end{frame} 81 | 82 | \begin{frame}{Test Cases Designing: ``Boundary Input"} 83 | Boundary cases are those input that pushes the program to the ``boundary": 84 | \begin{itemize} 85 | \item They are base case in recursion. 86 | \item They pushes program to the edge of used datatype range. 87 | \item Any point that is ``tricky". For example in a \texttt{gcd} program you should remember to test the input where one argument is a multiple of another. Any input that will trigger a special treatment. 88 | \end{itemize} 89 | For our previous example some good test cases will be: 90 | \begin{itemize} 91 | \item \texttt{""} Empty string 92 | \item \texttt{"1"} Single character string 93 | \item \texttt{123...321} 99 characters string, why 99? 94 | \item \texttt{"11"} Odd number (possibly) base case 95 | \end{itemize} 96 | \end{frame} 97 | 98 | \begin{frame}{Test Cases Designing: ``Random / Malicious input"} 99 | Those are inputs that does not make sense. You normally don't expect your users to supply such arguments, but often technically they can. 100 | 101 | For example you won't expect the user to input \texttt{I love lemonade} in a text box labeled \textit{What is your social security number?}. But technically your program can receive such input. 102 | 103 | It is often these situation that brings about the most trouble. These input can potentially crash the program. Or worse, construct special input that corrupts / extracts confidential data. 104 | 105 | The conclusion is: \alert{Never trust your user, not a single byte!} 106 | \begin{itemize} 107 | \item Random input, random bytes... 108 | \item Malicious input. 109 | \item Assume that your user will not listen to your warnings. E.g. input more than 10 characters when prompted \texttt{Input a string of less than 10 characters :}. 110 | \end{itemize} 111 | \end{frame} 112 | 113 | \begin{frame}{Test Cases Designing: Design with abstraction} 114 | It is very important to keep the abstraction, or specification in general in mind when trying to design test cases. 115 | \begin{itemize} 116 | \item The specification specifies the what inputs are ``normal", i.e. what are the inputs that fits ``REQUIRES" clause. 117 | \item The specification specifies the expected output. 118 | \item The specification often defines boundaries, the one value that divides valid input with invalid inputs. 119 | \item The specification often suggests program load in real world. 120 | \item The specification tells what inputs are considered ``invalid". 121 | \end{itemize} 122 | There is one more thing, the ``MODIFIES" clause. Often the code under testing produce (or relies on) side-effects. The ``MODIFIES" clause specify these things. 123 | 124 | \alert{Again we emphasize the importance of creating a clear abstraction!} 125 | \end{frame} 126 | 127 | \begin{frame}{A QA (Quality Assessment) engineer walks into a bar} 128 | The following is adapted from the work of \textit{Bill Sempf}'s twitter. 129 | \vspace{0.1in} 130 | A QA engineer walks into a bar 131 | \begin{itemize} 132 | \item Then he orders 0 beers. 133 | \item Then he orders 2 beers. 134 | \item Then he orders 999999999999 beers. 135 | \item Then he orders an \texttt{aardvark}. 136 | \item Then he orders \texttt{nullptr}. 137 | \item Then he orders -1 beers. 138 | \item Then he orders \texttt{3.14} beers. 139 | \item Then he orders \texttt{asnwikfjsdf}. 140 | \item Then he orders \texttt{>}. 141 | \item Finally, the QA engineer leaves without paying, comes back, and asks for the tab. 142 | \end{itemize} 143 | \end{frame} 144 | 145 | \begin{frame}{\textit{Unit test}, \textit{Regression test} and \textit{Integration Test} } 146 | \framesubtitle{Rome is not built over night. So are softwares.} 147 | 148 | We now introduce you to some software engineering terms. 149 | 150 | \begin{itemize} 151 | \item Often software are first designed by an architect, partitioned into \textit{modules}s. 152 | \item Programmers code each module independently. They write \texttt{Unit Tests} for each module. 153 | \item When the modules are put together, architect team creates \textit{Integration tests} 154 | \item The collection of test cases are called a \textit{Test Suite} 155 | \item The team will keep updating the software. After each change, a test suite a will be run to ensure the change didn't happen to break anything. This is called a \textit{Regression Test} 156 | \end{itemize} 157 | \end{frame} 158 | 159 | \begin{frame}{Test automation} 160 | From you own experience: 161 | \begin{itemize} 162 | \item Testing is actually pretty common task. 163 | \item It takes time to create driver programs to run the tests. 164 | \item It takes time (and code) to create test cases. You often need to manually calculate the expected output. 165 | \item It takes time (and code) to analyze test results. To keep track what goes wrong, especially you. 166 | \end{itemize} 167 | This calls for \textit{Test Automation} and \textit{Testing Framework}s, a testing framework is (often) a piece of library that does the following: 168 | \begin{itemize} 169 | \item Runs test cases automatically. 170 | \item Manages the test cases, selects what to run and what not. 171 | \item Automatically sets-up the test environment (test fixtures). 172 | \item Automatically keeps track of what's OK and what goes wrong. 173 | \item And much more... 174 | \end{itemize} 175 | \end{frame} 176 | 177 | \begin{frame}[fragile]{\textit{Google Test} framework} 178 | Project Homepage: \texttt{https://github.com/google/googletest} 179 | Introduction is available if you \hyperlink{https://github.com/google/googletest/blob/master/googletest/docs/Primer.md}{click here} 180 | 181 | Here is a portion of code I used to test my VE281 project: 182 | \begin{minted}{c++} 183 | TEST_P(SelectionTest, DSelection) { 184 | int *d= dataset->getCopied(); 185 | int size = dataset->getSize(); 186 | for (int i = 0; i < size; ++i) { 187 | int val = deterministicSelection(d, size, i); 188 | int answer = dataset->select(i); 189 | ASSERT_EQ(val, answer); 190 | delete[] d; 191 | d = dataset->getCopied(); 192 | } 193 | delete[] d; 194 | } 195 | \end{minted} 196 | \end{frame} 197 | 198 | \begin{frame}{Google Test in CLion} 199 | \vspace{-0.3in} 200 | 201 | \begin{figure} 202 | \centering 203 | \includegraphics[scale=0.25]{fig/rc6gtest} 204 | \end{figure} 205 | \end{frame} 206 | 207 | \subsection{Engineering robustness: Exceptions} 208 | \begin{frame}{Breaking the abstraction} 209 | The central question that goes around with exceptions are: 210 | \begin{center} 211 | \structure{What if assumptions of an abstraction is broken?} 212 | \end{center} 213 | Note that this should be understand in a broader sense. Any program runs under some assumption. For example, 214 | \begin{itemize} 215 | \item There is enough system memory for your program. 216 | \item There is enough space when you need to create a file. 217 | \item Input outside \texttt{REQUIRES} clause never happens. 218 | \item Your computer have an available Internet connections. 219 | \item ... 220 | \end{itemize} 221 | All these things constitutes the assumption you made about your abstractions. But it certainly could happen that one (or more) of them are broken. This could due to hardware limitations, or more likely due to an error in programming. 222 | \end{frame} 223 | 224 | \begin{frame}[fragile]{Fail-fast \& ``I give up."} 225 | \alert{There is absolutely no point to save a flawed processess}. This is called the fail-fast fast. 226 | \begin{itemize} 227 | \item The program is already in an non-recoverable state 228 | \item It is probably due to a programming error 229 | \item Error might propagate, crash site far from source. 230 | \item May corrupt data. Programs can be fixed, data can't. 231 | \item Best strategy is to quit gracefully. 232 | \end{itemize} 233 | A typical situation: 234 | \begin{minted}{c++} 235 | void foo() { 236 | int *p = malloc(sizeof(int) * 10); 237 | // This should always success unless lacking memory 238 | assert(!p); 239 | // Do something with p 240 | free(p); 241 | } 242 | \end{minted} 243 | \end{frame} 244 | 245 | \begin{frame}[fragile]{``It's my problem."} 246 | The attempt is to make the function essentially a ``total" function. Essentially this strategy says 247 | \begin{center} 248 | \structure{``Invalid inputs are part of my abstraction"} 249 | \end{center} 250 | Which also implies testing for invalid inputs! An (not so good) example: 251 | \begin{minted}{c++} 252 | // Checks if all letters ina string are capital 253 | bool isAllCapital(char* str, int size) { 254 | int len = strlen(str); 255 | if (size != len + 1) len = size; // Input validation 256 | for (int i = 0; i <= len; i++) 257 | if (*str < 'A' || *str > 'Z') 258 | return false; 259 | return true; 260 | } 261 | \end{minted} 262 | \end{frame} 263 | 264 | \begin{frame}{``It's my problem."} 265 | There are some serious problem with this approach: 266 | \begin{itemize} 267 | \item Function might not have well defined ``default" value. 268 | \item It might hard to guess a ``default" value. 269 | \end{itemize} 270 | Regardless above problem, much more serious problem comes with error propagation. There is probably a reason why this input is valid. It's most likely because you code is incorrect (in some sense) or your running environment is problematic (stack overflowed, for example). 271 | 272 | You need to understand whenever you took this approach, you are trying to fix an already ``broken" program, going against the fail-fast principal. 273 | 274 | \begin{itemize} 275 | \item You could end up crashing somewhere far from the root cause. 276 | \item Your program could behave wired. Since your abstraction includes treatment of ``special cases" 277 | \end{itemize} 278 | \end{frame} 279 | 280 | \begin{frame}[fragile]{``It's not my problem"} 281 | The problem of above approaches is significant because they are trying to deal with errors that does not come from themselves. The root cause of these invalid inputs are somewhere else, probably only known by their caller. 282 | 283 | The natural idea would be to find a method to pass the information up the chain of calling, a natural way of doing so is by return \textit{Error Codes}. 284 | 285 | There are in general two ways to do so: 286 | \begin{minted}{c} 287 | // Returns negative value if error 288 | int fact1(int n); 289 | // Returns value signifies error, zero indicates no error 290 | // Actual result is put into *rst 291 | int fact2(int n, int* rst); 292 | \end{minted} 293 | In some cases libraries use a global variable to store the error code of last function call. 294 | \end{frame} 295 | 296 | \begin{frame}[fragile]{Problem with error codes} 297 | Both methods have severe draw back: 298 | \begin{minted}{c++} 299 | double tan(double rad); 300 | \end{minted} 301 | Function \texttt{fun} could return anything in \texttt{double}, now what should you use for error code? 302 | \begin{minted}{c++} 303 | int foo(double rad) { 304 | double rst = 0.0;int err = tan(rad, &rst); 305 | } 306 | \end{minted} 307 | The second makes calling ``unnatural. Also performance drawbacks. 308 | \begin{itemize} 309 | \item Error code can be ignored. The worse thing than crashing on errors is an unattended error 310 | \item Error code needs to be passed up the stream. Sometimes the direct caller also don't have a clue, it needs to pass it on. 311 | \item Breaks abstraction. 312 | \end{itemize} 313 | \end{frame} 314 | 315 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 316 | We know introduce you to \textit{Structural Error Handling}. The following is a try block 317 | \begin{minted}{c++} 318 | // (1) 319 | try { 320 | // (2) (may throw;) 321 | } catch (const T& e) { 322 | // (3) ... 323 | } 324 | // (4) 325 | \end{minted} 326 | Just like usually \texttt{if}, \texttt{while} blocks, a \texttt{try} block marks a special control flow, featuring (usually) 2 different code execution paths. 327 | \begin{itemize} 328 | \item Path 1. Exception raised in (2), we go (1) (2, partial) (3) (4). 329 | \item Path 2. Normally we go (1) (2) (4). 330 | \end{itemize} 331 | Path 1 assumes the exception is caught. Further discussion on next slide. 332 | \end{frame} 333 | 334 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 335 | An concrete example. 336 | \begin{minted}{c++} 337 | try { 338 | cout << "hello!" << endl; throw 123; 339 | cout << "Goodbye" << endl; 340 | } catch (int x) { 341 | cout << "Integer Exception"; 342 | } 343 | \end{minted} 344 | Prints \texttt{"Hello//Interger Exception"} 345 | \begin{itemize} 346 | \item A \texttt{throw} clause raise an exception (of arbitrary type). 347 | \item When an exception is raise, immediate stop the following execution and go for smallest enclosing \texttt{try} block. 348 | \item If there isn't one, terminates program. 349 | \item If there is one, begin matching \texttt{catch} clauses. 350 | \item If found, we say the error is \textit{handled}, begin executing after \texttt{try}. If not, terminates program. 351 | \end{itemize} 352 | \end{frame} 353 | 354 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 355 | A try block can be matched no matter how deep in the function. The following example is just for demonstration! \alert{It is NOT a good practice!} 356 | \begin{minted}{c++} 357 | int foo(int n, int prod) { 358 | if (n == 0) throw prod; 359 | foo (n - 1, n * prod); 360 | } 361 | int realFact(int n) { 362 | try { 363 | foo(n , 1); cout << "LaLaLa"; 364 | } catch (const int& x) { 365 | cout << "Aloha!" << endl; 366 | return x; 367 | } 368 | } // Prints Only "Aloha!". 369 | \end{minted} 370 | 371 | \end{frame} 372 | 373 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 374 | An exception cannnot be overlooked! Unhandeled exception terminates the program. 375 | \begin{minted}{c++} 376 | int fact(int n) { 377 | if (n < 0) throw n; 378 | if (n == 0) return 1; 379 | return n * fact(n - 1); 380 | } 381 | int main() { int x = fact(-50); } 382 | \end{minted} 383 | Note we use the word ``Teriminate". There is an difference in \textit{crashing} and \textit{terminating}. 384 | 385 | The first term indicates the program is stopped by force (by the operating system), immediately. 386 | 387 | The second one indicates a seriers events will happen (for example, clearing the buffer of \texttt{cout}). The program terminates (somewhat) gracefully. 388 | \end{frame} 389 | 390 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 391 | The smallest enclosing \texttt{try} block gets to handle the exception 392 | \begin{minted}{c++} 393 | void foo() {throw -1;} 394 | void bar() { 395 | try{ foo(); }catch(double e){cout << "bar!";} 396 | cout << "Slotted Aloha!"; 397 | } 398 | void rua() { 399 | try{ bar(); }catch(int e){cout << "rua!";} 400 | cout << "Alright!"; 401 | } 402 | void baz() { 403 | try{ rua(); }catch(int e){cout << "baz!";}} 404 | int main() {baz();} 405 | \end{minted} 406 | Above programs prints \texttt{rua!Alright!}. It terminates normally. 407 | 408 | \end{frame} 409 | 410 | \begin{frame}[fragile]{Structural Error handling: \texttt{try}, \texttt{catch} and \texttt{throw}} 411 | An exception can be rethrown after being caught in a \texttt{catch} block. This is useful since you might need clean up, although you don't known how to deal with the error. It is also possible to throw a different exception. 412 | \begin{minted}{c++} 413 | void foo() {throw -1;} 414 | void bar() { 415 | int *p = new int(10); 416 | try{ foo(); } 417 | catch(...){delete p; cout << "bar!"; throw; }} 418 | void rua() { 419 | try{ bar(); }catch(int e){cout << "rua!"; throw 1.0;}} 420 | int main() {rua();} 421 | \end{minted} 422 | Above programs prints \texttt{bar!rua!}. It terminates due to an unhandled exception \texttt{1.0}. 423 | \end{frame} 424 | 425 | \begin{frame}[fragile]{Rules for matching for \texttt{catch}} 426 | The rules for matching \texttt{catch} is given as follows: 427 | \begin{enumerate} 428 | \item First found first match. 429 | \item Match only with \alert{exact} same type. If the exception is an class instance, also matches with it's base catch. 430 | \item \texttt{catch(...)} matches everything. 431 | \end{enumerate} 432 | \begin{columns} 433 | \column{.5\textwidth} 434 | 435 | \vspace{-0.2in} 436 | \begin{minted}{c++} 437 | try{int x = 1; throw x;} 438 | catch(long int li) { 439 | // No match 440 | } catch (int x) { 441 | // Match here 442 | } catch (...) { 443 | // Already matched 444 | } 445 | \end{minted} 446 | 447 | \column{.5\textwidth} 448 | 449 | \vspace{-0.2in} 450 | \begin{minted}{c++} 451 | try{int x = 1; throw x;} 452 | catch(long int li) { 453 | // No match 454 | } catch (double x) { 455 | // No match 456 | } catch (...) { 457 | // Matched 458 | } 459 | \end{minted} 460 | 461 | \end{columns} 462 | \end{frame} 463 | 464 | \begin{frame}[fragile]{Exception Hierarchy} 465 | The fact that exception instances can be caught by their base class type is actually very useful in reality. You can catch a ``class" of exceptions while leaving others un touched. 466 | \begin{minted}{c++} 467 | class Exception {}; 468 | class IntegerExecption : public Exception {}; 469 | class FileExecption : public Exception {}; 470 | class FileNotFound : public FileExecption {}; 471 | class PermissionDenied : public FileExecption {}; 472 | void doSomethingToFile(string filename); 473 | void foo(int n) { 474 | string file = "str" + to_string(n); 475 | try { doSomethingToFile(file) } 476 | catch (const FileExecption& e) { 477 | cout << "Something wrong with File"; 478 | } } 479 | \end{minted} 480 | \end{frame} 481 | 482 | \begin{frame}{Exception Hierarchy in standard library} 483 | \vspace{-0.2in} 484 | \begin{figure} 485 | \centering 486 | \includegraphics[scale=0.55]{fig/rc6stdexp} 487 | \end{figure} 488 | \end{frame} 489 | 490 | \begin{frame}{Tips} 491 | \begin{enumerate} 492 | \item Throw by value and catch by const reference. 493 | \item \texttt{throw} only on real exceptions 494 | \end{enumerate} 495 | \begin{block}{Throw by value} 496 | When an exception is raised, the programming is doing sort of recovery. The function that throws the exceptions most likely is going to terminate. 497 | Thus throwing reference (or address) to local objects won't make sense at the handling site. 498 | \end{block} 499 | \begin{block}{Catch by const reference} 500 | The very reason that you need to catch exceptions by reference is simply because exceptions can contain virtual functions. 501 | \end{block} 502 | \end{frame} 503 | 504 | 505 | 506 | -------------------------------------------------------------------------------- /week5.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 5} 2 | \subsection{Mechanism behind function calling} 3 | \begin{frame}{Memory Layout} 4 | Before function calling we would like to first give a brief introduction to the memory organization of the system 5 | \begin{columns} 6 | \column{.5\textwidth} 7 | \vspace{0.05in} 8 | 9 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 10 | \begin{leftwordgroup}{Low} 11 | \bitbox{16}{Text} 12 | \end{leftwordgroup}\\ 13 | \begin{leftwordgroup}{} 14 | \bitbox{16}{Consts} 15 | \end{leftwordgroup}\\ 16 | \begin{leftwordgroup}{} 17 | \bitbox{16}{Statics} 18 | \end{leftwordgroup}\\ 19 | \begin{leftwordgroup}{High} 20 | \wordbox[lrt]{1}{Heap $\downarrow$} \\ 21 | \skippedwords \\ 22 | \bitbox[lrb]{16}{Stack $\uparrow$} 23 | \end{leftwordgroup}\\ 24 | \end{bytefield} 25 | 26 | * This graph is up-side-down. 27 | 28 | \column{.5\textwidth} 29 | \vspace{0.05in} 30 | \structure{Explanation} 31 | \begin{itemize} 32 | \item ``Text", just ``code" 33 | \item ``consts", not like \texttt{const int const}, but string literals, \texttt{"Hello world"}. 34 | \item ``Statics", global variables, static variables in functions. ``static" refers to lifetime. 35 | \item ``Heap", where you \texttt{new}. 36 | \item ``Stack", everything local. Arugments, return values, return addresses ... 37 | \end{itemize} 38 | \end{columns} 39 | \end{frame} 40 | 41 | \begin{frame}[fragile]{Element in a stack} 42 | \begin{columns} 43 | 44 | \column{.5\textwidth} 45 | \vspace{-0.15in} 46 | 47 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 48 | \begin{leftwordgroup}{} 49 | \bitbox{16}{z = 4 @ foo(3)} 50 | \end{leftwordgroup}\\ 51 | \begin{leftwordgroup}{} 52 | \bitbox{16}{x = 3 @ foo(3)} 53 | \end{leftwordgroup}\\ 54 | \begin{leftwordgroup}{} 55 | \bitbox{16}{Ret = ?} 56 | \end{leftwordgroup}\\ 57 | \begin{leftwordgroup}{\texttt{foo}} 58 | \bitbox{16}{RA = \&CALLS + 1} 59 | \end{leftwordgroup}\\ 60 | \begin{leftwordgroup}{} 61 | \bitbox{16}{q = ? @ main()} 62 | \end{leftwordgroup}\\ 63 | \begin{leftwordgroup}{} 64 | \bitbox{16}{p = 3 @ main()} 65 | \end{leftwordgroup}\\ 66 | \begin{leftwordgroup}{\texttt{main}} 67 | \bitbox{16}{...} 68 | \end{leftwordgroup} 69 | \end{bytefield} 70 | \column{.5\textwidth} 71 | \vspace{-0.2in} 72 | \begin{minted}{c++} 73 | int foo(int x) { 74 | int z = x + 1; 75 | /* Here */ 76 | return z + x; 77 | } 78 | int main() { 79 | int p = 3; 80 | p = foo(p); // <- CALLS 81 | int q = 10; 82 | } 83 | \end{minted} 84 | \end{columns} 85 | \vspace{0.1in} 86 | The stack maintains the following information 87 | \begin{itemize} 88 | \item Function arguments. They are evaluated and on to the stack. 89 | \item Local variables (arrays). They are reserved before initialized. 90 | \item Return value and return address. Return address tells which instruction to pick up when the call returned. 91 | \end{itemize} 92 | \end{frame} 93 | 94 | \begin{frame}{Remarks} 95 | \begin{block}{Calling mechanism is about \textit{Abstraction}} 96 | Calling mechanism is designed in such way to support procedural abstraction. In order for the abstraction to work, we require 97 | \begin{center} 98 | \structure{Each function call is independent} 99 | \end{center} 100 | This is especially important if you have recursion calls. 101 | \end{block} 102 | 103 | \begin{block}{Calling mechanism is platform dependent} 104 | \begin{itemize} 105 | \item Calling mechanism is neither specified by standard, nor unique! 106 | \item Whose responsibility to manage arguments? Caller / callee? 107 | \item Compiler might optimize unused variables out. 108 | \item Compiler might use register to store information. 109 | \item Compiler is allowed optimize the entire stack frame out. 110 | \end{itemize} 111 | \end{block} 112 | \end{frame} 113 | 114 | \begin{frame}{Puzzles for \alert{FFFUUUNNNNN}!} 115 | Under standing calling stack is most useful in finding out what has gone wrong when you observe strange behavior of your program. This is very much like solving puzzles. 116 | 117 | We now give you a few such puzzles to entertain you. Note all the code we gave you below contains \alert{undefined behaviors} so don't be surprised if you cannot reproduce this problem. 118 | 119 | This is actually worth noting. Many undefined behaviors would cause different behavior since given different situation on the stack. 120 | 121 | \begin{itemize} 122 | \item This code works on my computer but crashed on OJ. 123 | \item This code crashes / malfunctions if I change unrelated things. 124 | \item Student: ``TA, my code can't work!". \\ 125 | TA\qquad: ``Can you demo? I can't reproduce your problem"\\ 126 | Student: ``Suddenly I can't Either! But it crashes on OJ!" 127 | \item This code randomly crashes. 128 | \end{itemize} 129 | \end{frame} 130 | 131 | \begin{frame}[fragile]{Puzzle 0: Why not VLA?} 132 | \textit{Variable Length Arrays} (VLA) are arrays whose size are determined at compile time. For example in the following code \texttt{arrX} is a VLA, and \texttt{arrY} is a usual array. 133 | \begin{minted}{c} 134 | void foo() {int t = 20; int arrX[t * t]; int arrY[400];} 135 | \end{minted} 136 | But both C++ and C choose \textbf{not} to support this language feature (above code won't compile). Explain what's the underlying reason. 137 | 138 | \pause 139 | \begin{block}{Explanation} 140 | What would be the impact of this feature? Variable length array will consume variable amount of memory. 141 | 142 | If the array is a local variable. The stack frame size of the function cannot be determined in compile time. 143 | 144 | The need to know the size of a function's compile time stack frame size is centric in language design. 145 | \end{block} ` 146 | \end{frame} 147 | 148 | \begin{frame}[fragile]{Puzzle 1: Orders matter} 149 | \texttt{$-->$ code/rc5pz1/a.cpp} 150 | \inputminted{c++}{code/rc5pz1/a.cpp} 151 | User inputed \texttt{Hello}, symptoms are: 152 | \begin{itemize} 153 | \item Program crashes after printing 4 times of \texttt{Hello}. 154 | \item Program runs fines if change input to \texttt{Bad}. 155 | \item Program doesn't crash if switch \texttt{char a[4]} and \texttt{int x = 4}. But the program keeps printing \texttt{Hello}. 156 | \end{itemize} 157 | \end{frame} 158 | 159 | \begin{frame}{Solution 1} 160 | \begin{columns} 161 | \column{.5\textwidth} 162 | 163 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 164 | \begin{leftwordgroup}{4B} 165 | \bitbox{16}{s.x = 4 @ foo()} 166 | \end{leftwordgroup}\\ 167 | \begin{leftwordgroup}{1B} 168 | \bitbox{16}{s.a[0] @ foo()} 169 | \end{leftwordgroup}\\ 170 | \begin{leftwordgroup}{1B} 171 | \bitbox{16}{s.a[1] @ foo()} 172 | \end{leftwordgroup}\\ 173 | \begin{leftwordgroup}{1B} 174 | \bitbox{16}{s.a[2] @ foo()} 175 | \end{leftwordgroup}\\ 176 | \begin{leftwordgroup}{1B} 177 | \bitbox{16}{s.a[3] @ foo()} 178 | \end{leftwordgroup}\\ 179 | \begin{leftwordgroup}{\texttt{foo}} 180 | \bitbox{16}{RA = !!} 181 | \end{leftwordgroup}\\ 182 | \begin{leftwordgroup}{\texttt{main}} 183 | \bitbox{16}{...} 184 | \end{leftwordgroup} 185 | \end{bytefield} 186 | 187 | Return address is corrupted. 188 | 189 | \column{.5\textwidth} 190 | 191 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 192 | \begin{leftwordgroup}{1B} 193 | \bitbox{16}{s.a[0] @ foo()} 194 | \end{leftwordgroup}\\ 195 | \begin{leftwordgroup}{1B} 196 | \bitbox{16}{s.a[1] @ foo()} 197 | \end{leftwordgroup}\\ 198 | \begin{leftwordgroup}{1B} 199 | \bitbox{16}{s.a[2] @ foo()} 200 | \end{leftwordgroup}\\ 201 | \begin{leftwordgroup}{1B} 202 | \bitbox{16}{s.a[3] @ foo()} 203 | \end{leftwordgroup}\\ 204 | \begin{leftwordgroup}{4B} 205 | \bitbox{16}{s.x = !! @ foo()} 206 | \end{leftwordgroup}\\ 207 | \begin{leftwordgroup}{\texttt{foo}} 208 | \bitbox{16}{RA = \&main + 1} 209 | \end{leftwordgroup}\\ 210 | \begin{leftwordgroup}{\texttt{main}} 211 | \bitbox{16}{...} 212 | \end{leftwordgroup} 213 | \end{bytefield} 214 | 215 | Variable \texttt{s.x} is corrupted. 216 | \end{columns} 217 | 218 | \end{frame} 219 | 220 | \begin{frame}[fragile]{Puzzle 2: Missing return value?} 221 | \texttt{$-->$ code/rc5pz2/a.cpp} 222 | \inputminted{c++}{code/rc5pz2/a.cpp} 223 | This code is supposed to keeping squaring a number until it's greater than 100. 224 | \begin{itemize} 225 | \item Program output random number if c/with \texttt{g++ a.cpp} 226 | \item Program always return 225 if c/with \texttt{g++ -O1 a.cpp} 227 | \item Program spits random number if c/with \texttt{g++ -O1 a.cpp}, if we change ``\texttt{foo(x);}" to ``\texttt{y = foo(x);}". 228 | \end{itemize} 229 | \end{frame} 230 | 231 | \begin{frame}{Solution 2} 232 | \begin{columns} 233 | \column{.5\textwidth} 234 | 235 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 236 | \begin{leftwordgroup}{} 237 | \bitbox{16}{x = 225 @ foo(225)} 238 | \end{leftwordgroup}\\ 239 | \begin{leftwordgroup}{} 240 | \bitbox{16}{Ret = 225} 241 | \end{leftwordgroup}\\ 242 | \begin{leftwordgroup}{\texttt{foo}} 243 | \bitbox{16}{RA = \&foo(15)} 244 | \end{leftwordgroup}\\ 245 | \begin{leftwordgroup}{} 246 | \bitbox{16}{x = 225 @ foo(15)} 247 | \end{leftwordgroup}\\ 248 | \begin{leftwordgroup}{} 249 | \bitbox{16}{Ret = ?} 250 | \end{leftwordgroup}\\ 251 | \begin{leftwordgroup}{\texttt{foo}} 252 | \bitbox{16}{RA = \&main} 253 | \end{leftwordgroup}\\ 254 | \begin{leftwordgroup}{\texttt{main}} 255 | \bitbox{16}{...} 256 | \end{leftwordgroup} 257 | \end{bytefield} 258 | 259 | Without optimization 260 | \column{.5\textwidth} 261 | 262 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 263 | \begin{leftwordgroup}{} 264 | \bitbox{16}{x = 225 @ foo(225)} 265 | \end{leftwordgroup}\\ 266 | \begin{leftwordgroup}{} 267 | \bitbox{16}{Ret = 225} 268 | \end{leftwordgroup}\\ 269 | \begin{leftwordgroup}{\texttt{foo}} 270 | \bitbox{16}{RA = \&main} 271 | \end{leftwordgroup}\\ 272 | \begin{leftwordgroup}{\texttt{main}} 273 | \bitbox{16}{...} 274 | \end{leftwordgroup} 275 | \end{bytefield} 276 | 277 | After optimization 278 | \end{columns} 279 | \end{frame} 280 | 281 | \begin{frame}[fragile]{Puzzle 2.5: Who moved my cheese?} 282 | \texttt{$-->$ code/rc5pz25/a.cpp} 283 | \inputminted{c++}{code/rc5pz25/a.cpp} 284 | 285 | We observe the output to be \texttt{-1}. However we haven't changed the variable \texttt{cheese}. Who \texttt{mov}-ed my \texttt{cheese}. 286 | \end{frame} 287 | 288 | \begin{frame}{Solution 2.5} 289 | \begin{columns} 290 | 291 | \column{.5\textwidth} 292 | \vspace{-0.2in} 293 | \begin{bytefield}[leftcurly=., leftcurlyspace=0pt]{16} 294 | \begin{leftwordgroup}{} 295 | \bitbox{16}{cheese = !! @ foo()} 296 | \end{leftwordgroup}\\ 297 | \begin{leftwordgroup}{} 298 | \bitbox{16}{...} 299 | \end{leftwordgroup}\\ 300 | \begin{leftwordgroup}{\texttt{foo}} 301 | \bitbox{16}{RA = \&main} 302 | \end{leftwordgroup}\\ 303 | \begin{leftwordgroup}{} 304 | \bitbox{16}{arr[0][0] @ main()} 305 | \end{leftwordgroup}\\ 306 | \begin{leftwordgroup}{} 307 | \bitbox{16}{arr[0][1] @ main()} 308 | \end{leftwordgroup}\\ 309 | \begin{leftwordgroup}{} 310 | \bitbox{16}{... @ main()} 311 | \end{leftwordgroup}\\ 312 | \begin{leftwordgroup}{} 313 | \bitbox{16}{arr[1][0] @ main()} 314 | \end{leftwordgroup}\\ 315 | \begin{leftwordgroup}{} 316 | \bitbox{16}{... @ main()} 317 | \end{leftwordgroup}\\ 318 | \begin{leftwordgroup}{} 319 | \bitbox{16}{Ret = ?} 320 | \end{leftwordgroup}\\ 321 | \begin{leftwordgroup}{} 322 | \bitbox{16}{RA = ...} 323 | \end{leftwordgroup}\\ 324 | \begin{leftwordgroup}{\texttt{main}} 325 | \bitbox{16}{...} 326 | \end{leftwordgroup} 327 | \end{bytefield} 328 | \column{.5\textwidth} 329 | 330 | \begin{itemize} 331 | \item The loop out-of-bound. 332 | \item How 2D arrays are stored. 333 | \item Understand how indexing works. 334 | \item We omit the arguments and return values of \texttt{foo} on the graph 335 | \end{itemize} 336 | \end{columns} 337 | \end{frame} 338 | 339 | \begin{frame}[fragile]{Puzzle 3: A hijack} 340 | For this puzzle to work you might need to turn off \textit{Address Space Layout Randomization} and set \texttt{-fno-stack-protector} in g++. 341 | 342 | \texttt{$-->$ code/rc5pz3/a.cpp} 343 | \inputminted{c++}{code/rc5pz3/a.cpp} 344 | 345 | The trick is a carefully constructed input: 346 | \begin{center} 347 | \texttt{voidsecretFunction2e34!2\&\&Q.\%x;"]} 348 | \end{center} 349 | We observe the output is \texttt{You shouldn't be here...} 350 | 351 | The question is how does this happen, since \texttt{secretFunction} is not called at all? 352 | \end{frame} 353 | 354 | \begin{frame}[fragile]{Stack unwinding / unrolling} 355 | Hope you still remember \textit{constructors} and \textit{destructors}! 356 | 357 | When the function returns, it not only simply discards the stack space, it actually \textit{DESTROY}s the local objects, essentially calling their deconstructors. 358 | 359 | This is a very useful feature! We can use this feature to automatically release resources. Consider the following \texttt{File} class. 360 | 361 | \texttt{$-->$ code/rc5unroll/file.h} 362 | \inputminted{c++}{code/rc5unroll/file.h} 363 | \end{frame} 364 | 365 | \begin{frame}[fragile]{Stack unwinding / unrolling} 366 | The following code executes utilizes the above code: 367 | \texttt{$-->$ code/rc5unroll/a.cpp} 368 | \inputminted{c++}{code/rc5unroll/a.cpp} 369 | We paste the output: 370 | \inputminted{text}{code/rc5unroll/out} 371 | The files clean themselves up after returned. 372 | \end{frame} 373 | 374 | \begin{frame}[fragile]{Stack overflow} 375 | A final point is that in general your stack is rather small, compared to the heap. 376 | 377 | We refer to an empirical experiment done by \textit{Bruno Haible} in 2009. 378 | 379 | \begin{minted}{text} 380 | - glibc i386, x86_64 7.4 MB 381 | - Cygwin 1.8 MB 382 | - Solaris 7..10 1 MB 383 | - MacOS X 10.5 460 KB 384 | - OpenBSD 4.0 64 KB 385 | \end{minted} 386 | 387 | Usually heap size is hundreds of MB, if not GB on a modern computer. It could happen that you ran out of stack space. In such situation we say you encountered a \textit{stack overflow}, because: 388 | \begin{itemize} 389 | \item Maybe you recurse too deep (Why?). 390 | \item Maybe you declare large arrays in the stack. 391 | \end{itemize} 392 | \end{frame} 393 | 394 | \subsection{Recurse Recursively} 395 | \begin{frame}{Recursion is the art of abstraction} 396 | A typical processes of designing a recursive function goes as follows: 397 | \begin{itemize} 398 | \item Be very clear first about the abstraction of the function you needed to input. 399 | \item Specify a base case, a set of input where the answer is immediately known (or can be calculated in a few steps). 400 | \item Assume that your abstraction actually works for input ``simpler" than the current input (closer to the base case). Use this assumption to build your program. 401 | \end{itemize} 402 | You might find these steps surprisingly similar to a mathematical induction. That's true. They are similar and that's very useful. 403 | \end{frame} 404 | 405 | \begin{frame}[fragile]{Recursion is the art of abstraction} 406 | \begin{minted}{c++} 407 | // REQUIRES: list is not empty 408 | // EFFECTS: returns largest element in the list 409 | int largest(list_t list) { 410 | int first = list_first(list); 411 | list_t rest = list_rest(list); 412 | if (list_isEmpty(rest)) return first; 413 | return max(first, largest(rest)); 414 | } 415 | \end{minted} 416 | \begin{itemize} 417 | \item The abstraction is specified in the header. 418 | \item The base base is where list contains just one element. 419 | \item In the last line, assume abstraction works in simpler case (hope you see why \texttt{rest} is ``simpler" than \texttt{list}). Thus \texttt{largest(rest)} returns the largest of the remaining list. 420 | \item The largest number can either be the largest of the remaining number, or the first number. 421 | \end{itemize} 422 | \end{frame} 423 | 424 | \begin{frame}[fragile]{Example: Quick sort algorithm} 425 | A quick sort algorithm sorts a array in a quick way (I know that sound like bullshxx!). But list basic steps as following: 426 | \begin{itemize} 427 | \item Select an element in the array. We simply use the first element. We call this element \texttt{pivot} 428 | \item We need to \textit{partition} the array. We need to move the elements less than the pivot to the left and elements larger than pivot to the right. Note we assume on the order of the elements left of the pivot (or elements on the right of the pivot). 429 | \begin{minted}{text} 430 | 6 5 3 8 -1 7 3 9 11 -4 | 5 3 -1 3 -4 6 8 7 9 11 431 | |<- pivot | |<- pivot 432 | \end{minted} 433 | \item Call \texttt{QuickSort} on the both sides of the pivot. 434 | \end{itemize} 435 | The majority of the work lies in the partition step. 436 | \end{frame} 437 | 438 | \begin{frame}{A usual Quick Sort} 439 | \texttt{$-->$ code/rc5qsort/nonrec.cpp} 440 | \inputminted{c++}{code/rc5qsort/nonrec.cpp} 441 | \end{frame} 442 | 443 | \begin{frame}[fragile]{Our Quick Sort} 444 | Suppose we are using our list interface (in the project!). 445 | \begin{itemize} 446 | \item Suppose \texttt{QuickSort} is a function that takes in a list and returns a sorted list. Remember this is abstraction. Base case is when the list is empty. 447 | \begin{minted}{c++} 448 | list_t qSort(list_t lst); // Returns sorted lst 449 | \end{minted} 450 | 451 | \item Our computation goes as follows, we first acquire a the partion-left part and partition-right part. We call \texttt{qSort} on both parts and concatenate left, pivot and right part: 452 | \begin{minted}{c++} 453 | list_t sorted = cat(qSort(left), pivot, qSort(right)) 454 | \end{minted} 455 | \item The left part are simply numbers less than pivot, the right part are simply numbers greater than pivot. 456 | \begin{minted}{c++} 457 | list_t left = filterLess(lst, pivot); 458 | list_t right = filterGreater(lst, pivot); 459 | \end{minted} 460 | \item And we are done. Now we simply copy everything into one place. 461 | \end{itemize} 462 | \end{frame} 463 | 464 | \begin{frame}[fragile]{Our Quick Sort} 465 | And here is the famous (almost) one-line quick sort 466 | \begin{minted}{c++} 467 | list_t qSort(list_t lst) { 468 | if (isEmpty(lst)) return lst; 469 | int pivot = list_first(lst); 470 | return concatenate( 471 | qSort(filterLess(list, pivot)), 472 | pivot, 473 | qSort(filterGreater(list, pivot)) 474 | ); 475 | } 476 | \end{minted} 477 | Now it just leaves us to implement the filter function and the concatenate function. But these two functions should be very easy. You have implemented the filter function in your project right? 478 | \end{frame} 479 | 480 | \begin{frame}{Why not references and pointers?} 481 | Think about it, why this seems much easier (clearer, hopefully you do feel that way)? 482 | 483 | In the traditional code, all functions works on the same array. We must manually control the process of copying, moving, etc. We are thinking in terms of \textit{operations}, detailed step to be performed. 484 | 485 | But the the new code, we can now begin think of data. We stop focusing on the concrete steps, but simply 486 | \begin{center} 487 | What should I do with the data? \\What is the expected input and the expected output? 488 | \end{center} 489 | It is the computation we needed to focus. 490 | 491 | This is not easy. The immutability of the data and the fact that all functions are pure allows us to do such thing. Every function does calculation on its own and does not impact the outside world. 492 | \end{frame} 493 | 494 | \begin{frame}[fragile]{Bridging the old perspective} 495 | Consider the following problem: 496 | 497 | \vspace{0.1in} 498 | \structure{Write a function \texttt{isMoreOdd} that takes a list $(a_0, a_1, a_2, ..., a_n)$ and returns $\Sigma_{i=0}^n i^2a_i$ (we call this an $s$-sum) Assuming the list is non empty.} 499 | \vspace{0.1in} 500 | 501 | An example as follows: 502 | 503 | \begin{minted}{text} 504 | a_i: 6 5 3 8 -1 7 3 505 | i : 0 1 2 3 4 5 6 506 | \end{minted} 507 | 508 | We follow our usual steps. The abstraction is self-explanatory. The base case is also easy (a single element list). But the problem lies in the third step. 509 | 510 | It seems that knowing $s$-Sum for for the rest of the list doesn't help on the reducing the problem to a simpler point. 511 | 512 | It would still be most desirable to have some sort of ``accumulator", something that registers a partial sum, a piece of information that ``sums" up the elements before a certain point. 513 | \end{frame} 514 | 515 | \begin{frame}[fragile]{Accumulator passing style} 516 | This is still possible. Such construct is so common that gets its own name. We call this \textit{Accumulator passing style} (APS). 517 | 518 | \begin{minted}{c++} 519 | int helper(list_t remain, int index, int acc) { 520 | if (isEmpty(remain)) return acc; 521 | acc += index * index * list_first(remain); 522 | return helper(list_rest(remain), index + 1, acc); 523 | } 524 | list_t strangeSum(list_t list) { 525 | return helper(list, 0, 0); 526 | } 527 | \end{minted} 528 | 529 | How does this work? 530 | 531 | The essential idea is to sum up the necessary information into two (could be more) accumulators. We essentially created a sort of running sum. 532 | \end{frame} 533 | 534 | \begin{frame}[fragile]{Accumulator passing style} 535 | We then further note the abstraction of the helper function. 536 | 537 | The function \texttt{helper} takes the index of the first element in the remainder list and a partial sum of the elements before, and returns the $s$-sum of the entire list. 538 | 539 | In this way we transform our original problem of finding out \texttt{helper(list, 0, 0)}. On each recurse call, we extract the first element, and use it to update our accumulators, and passed that on to the next call. 540 | 541 | \begin{minted}{text} 542 | helper([6 5 3 8 -1 7 3], 0, 0) 543 | helper([5 3 8 -1 7 3], 1, 0) 544 | helper([3 8 -1 7 3], 2, 5) 545 | helper([8 -1 7 3], 3, 17) 546 | helper([-1 7 3], 4, 89) 547 | helper([7 3], 5, 73) 548 | helper([3], 6, 248) = helper([], 7, 356) :=356 549 | \end{minted} 550 | \end{frame} 551 | 552 | \begin{frame}{Remarks} 553 | \begin{block}{Understand APS in a broad sense} 554 | APS is extremely useful. In many sense this technique is very similar to loops, which you might feel more comfortable to deal with. On the other hand an accumulator can be more than just an sum of numbers. It could be any information you need to keep track of (for example, if the number before forms an arithmetic sequence, and if they do, what is the increment). 555 | \end{block} 556 | 557 | \begin{block}{Recursion and correctness} 558 | It's extremely difficult to write correct code! It would be nice if we can formally prove that our code is correct. Since the usual procedural code involves state, this proof can be very complex. 559 | 560 | But if you express the idea using abstraction, proving correctness is very simple and forward. A good recursion construction is almost always correct, and you can prove it! Write once and be free of testing and bug. What a nice thing! 561 | \end{block} 562 | \end{frame} -------------------------------------------------------------------------------- /week2.tex: -------------------------------------------------------------------------------- 1 | \section{RC Week 2} 2 | \subsection{OK, VE280. What is this course?} 3 | \begin{frame} 4 | \frametitle{How to write good code ${}^\text{and linked lists}$} 5 | \begin{block}{Writing Quality Code} 6 | \begin{description}[Motivation] 7 | \item[Taste] What kind of code are considered "good"? 8 | \item[Motivation] What benefit would such code give us? 9 | \item[Techique] What is the recipe for such code? 10 | \item[Tools] What language features does C++ provide for achieving this goal? How to use them? 11 | \end{description} 12 | \small{Good (Bad?) News: Exams will (mostly) test for the last point.} 13 | \end{block} 14 | \begin{block}{Elementary Data Structure} 15 | Singly linked lists, Doubly linked lists, Circular Arrays ... \ 16 | \end{block} 17 | \end{frame} 18 | \begin{frame}{OK, "Quality Code"?} 19 | It's very hard to give a definition. 20 | \begin{columns} 21 | \column[]{.5\textwidth} 22 | 23 | \begin{block}{Good Code} 24 | \begin{itemize} 25 | \item Good variable names 26 | \item Consistent indentation 27 | \item Well tested, documented 28 | \item D-R-Y, Don't repeat yourself 29 | \item High Coherence / Low coupling 30 | \item Open for extension, but closed for modification 31 | \end{itemize} 32 | \end{block} 33 | \column[]{.5\textwidth} 34 | \begin{block}{Bad Code} 35 | \begin{itemize} 36 | \item Bad Style 37 | \item 200+ lines in a one function 38 | \item Functions of 20+ Args 39 | \item Magic numbers everywhere 40 | \item Seriously you know bad code when you see one (write one). 41 | \end{itemize} 42 | \end{block} 43 | \end{columns} 44 | Many of them are related to \emph{Abstraction}. 45 | \end{frame} 46 | 47 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 48 | \framesubtitle{No abstraction} 49 | \begin{block}{The Requirement} 50 | \textit{CubedEnix (CE)} is trying to develop a third person shooting game called \textit{World of Armored Blizzard} (WOAB). In this game, AI will control a tank that can fire upon the player. A programmer \textit{Archer} is asked to implement this feature. 51 | \end{block} 52 | \begin{block}{The Solution} 53 | Archer propose to have a global variable \texttt{TANK} of class \texttt{Tank} to represent the tank. Archer than writes the following code. 54 | \begin{minted}{c++} 55 | ... 56 | Player target = TANK.aim(); TANK.fire(target); 57 | ... 58 | \end{minted} 59 | Archer feels happy, so does his boss. 60 | \end{block} 61 | \end{frame} 62 | 63 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 64 | \framesubtitle{No abstraction} 65 | \begin{block}{Change of Requirement} 66 | Players are complaining that the game is too easy. WOAB dev team decided to add 2 more AI controlled tanks. Again Archer is asked to implement it. 67 | \end{block} 68 | \begin{block}{The Solution} 69 | Archer decided to use 3 global variables \texttt{TANK0, TANK1, TANK2} of class \texttt{Tank}. He copies the original code into 3 different places and modify each of them. 70 | \begin{minted}{c++} 71 | ... Player target = TANK0.aim(); TANK0.fire(target); 72 | ... Player target = TANK1.aim(); TANK1.fire(target); 73 | ... Player target = TANK2.aim(); TANK2.fire(target); 74 | \end{minted} 75 | Archer feels happy, so does his boss. 76 | \end{block} 77 | \end{frame} 78 | 79 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 80 | \framesubtitle{No abstraction} 81 | \begin{block}{Change of Requirement} 82 | Within the next 2 months they increased number of tanks to 10. 1 year later, they (finally!) decided to play a sound effect when a tank fires. 83 | \end{block} 84 | \begin{block}{The Twist} 85 | Archer now has 10 copies! He needs to add a function call \texttt{playSound()} to each copy. Unfortunately he missed one location. Archer also doesn't test his code. Now Buggy code is released. 86 | 87 | Players are unhappy. His boss is unhappy. Archer is fired. Archer is unhappy. Lancer takes his job. 88 | \end{block} 89 | \end{frame} 90 | 91 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 92 | \framesubtitle{With Procedual Abstraction} 93 | \begin{block}{The Solution} 94 | Lancer decided to write a function that takes a \texttt{Tank} object as an argument. 95 | \begin{minted}{c++} 96 | // Argument: A non-null pointer to a Tank object. 97 | // Effect : Fires such tank on the current player. 98 | void tankFire(Tank* t) { 99 | playSound(); 100 | Player target = t->takeAim(); 101 | t->fire(target); 102 | } 103 | \end{minted} 104 | With this new design Lancer can easily change the number of \texttt{TANK}s in the game, or modify the how tanks fire by simply changing this single function. 105 | \end{block} 106 | \end{frame} 107 | 108 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 109 | \framesubtitle{With just procedual abstraction} 110 | \begin{block}{Change of Requirement} 111 | \small{You know what? Those player just can't be satisfied. WOAB dev team now decides to involve not just tanks but also battle ships and planes (and witches and dragons ...). Lancer is asked to implement "fire" feature for all of them.} 112 | \end{block} 113 | \begin{block}{The Twist} 114 | \small{Lancer is now in a tough situation. Clearly Tanks, Ships, Planes... are different things. Their attack would have different effects. There won't be a single function that works for all of them. 115 | 116 | Since Lancer didn't take VE280 seriously when he is in JI, Lancer falls back to copying the code for each "character" once. After 2 months, the code is no longer maintainable, and thus he is fired. Saber takes his job.} 117 | \end{block} 118 | \end{frame} 119 | 120 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 121 | \framesubtitle{With Data Abstraction} 122 | \begin{block}{The Solution} 123 | The key is to see the elephant in the room. What's the common characteristic of tanks, ships, dragons and witches? They all attack our player! 124 | \begin{minted}{c++} 125 | class IAttackPlayer { 126 | virtual void fire(Player p) = 0; 127 | virtual Player takeAim() = 0; 128 | } 129 | class Tank : public IAttackPlayer; 130 | class Ship : public IAttackPlayer; 131 | .... 132 | \end{minted} 133 | \end{block} 134 | \end{frame} 135 | 136 | \begin{frame}[fragile]{Head First \textit{Abstraction}} 137 | \framesubtitle{With Data Abstraction} 138 | \begin{block}{The Solution} 139 | Then we can modify the function: 140 | \begin{minted}{c++} 141 | // Argument: a object implements IAttackPlayer. 142 | // Effect : Fires such tank on the current player. 143 | void NpcFire(IAttackPlayer* t) { 144 | playSound(); 145 | Player target = t->takeAim(); 146 | t->fire(target); 147 | } 148 | \end{minted} 149 | In the above design Saber abstracted out what the thing "physically" is. She defines things by defining what it can do. 150 | \end{block} 151 | \end{frame} 152 | 153 | \begin{frame}{A few more words} 154 | \begin{block}{It's okay if You don't fully understand above story} 155 | That's gives you a good reason to learn it well. 156 | \end{block} 157 | \begin{block}{Can you talk something about projects?} 158 | Well, projects are mostly very direct. Be careful in the process and they should be pretty easy. Reserve around 5 days for them. You only have a limited number of trials each day. 159 | 160 | Remember it's easy to simply finish them. But to finish them elegantly trust me when I say it's hard. 161 | 162 | Yes, it's hard. But the outcome worth every minute spent. 163 | \end{block} 164 | \end{frame} 165 | 166 | \subsection{Your Linux Operating System} 167 | \begin{frame}{Linux as a operating system \textit{kernel}} 168 | \begin{block}{Operating systems as a resource manager} 169 | Operating systems manages your hardware. These includes computation resource (CPU, GPU), storage (Hard drive), communication resource (network)... 170 | \end{block} 171 | \begin{block}{The core of OS, a.k.a. \textit{kernel}} 172 | At the very heart of the OS there lies the kernel. This piece of software talks directly to the hardware. It provides a unified way of accessing your storage devices (Filesystems), graphic devices, network... 173 | \end{block} 174 | \begin{block}{``Linux" is first the name of the kernel} 175 | This implies you can actually change your desktop environment: fancier? go with Unity/KDE/Gnome. Light weight \& fast? go with LXDE or XFCE. 176 | \end{block} 177 | \end{frame} 178 | 179 | \begin{frame}{Flavors of Linux: \textit{Distributions}} 180 | \framesubtitle{Common Choices} 181 | \begin{small} 182 | This flexibility of choice allows to tailor the system towards our own need. Some commonly accepted configurations become "Distributions". 183 | \end{small} 184 | \begin{block}{Ubuntu Series} 185 | Maintained by Canonical, it's actually a series of distributions with different choice of desktop environment. Ubuntu / \textit{Unity}. Kubuntu / \textit{KDE}. Lubuntu / \textit{LXDE}. Xubuntu / \textit{XFCE}. Use \textit{apt}. 186 | \end{block} 187 | \begin{block}{Debian} 188 | Once the most widely use distribution, the father of Ubuntu [that's right :=)]. Package management system is \textit{apt} 189 | \end{block} 190 | \begin{block}{Fedora and RedHat Linux Enterprise} 191 | Maintained by Red Hat. Fedora is new and cutting edge. RedHat now focus on enterprises. Package Management is \textit{yum}. 192 | \end{block} 193 | \end{frame} 194 | 195 | \begin{frame}{Flavors of Linux: \textit{Distributions}} 196 | \framesubtitle{Uncommon choices} 197 | \begin{block}{Open SUSE} 198 | Maintained by german company SUSE. Focus on stability. 199 | \end{block} 200 | \begin{block}{Arch Linux} 201 | ROLLING UPDATE! Absolutely cutting edge. Great community and wiki. User is assumed to be experienced. Installation is done on command line. Package management system is \textit{pacman}. 202 | \end{block} 203 | \begin{block}{Linux From Scratch} 204 | Try this if you are absolutely interested in figuring out how everything works. 205 | \end{block} 206 | \begin{block}{Gentoo} 207 | Think LFS is crazy enough? Well this things compiles every piece of software you use FROM THE SOURCE! 208 | \end{block} 209 | \end{frame} 210 | 211 | \begin{frame}{Bash on Windows Subsystem for Linux} 212 | \begin{block}{Think big, with abstraction} 213 | For Linux programs, technically, you don't need an "real" linux kernel to run them. As long as you have some thing that looks like a real one (one that follows the same abstraction). 214 | \end{block} 215 | \begin{block}{Windows Subsystem for Linux} 216 | This year Microsoft actually release one. Installation guide is available \href{https://msdn.microsoft.com/zh-cn/commandline/wsl/install\_guide}{here(click me)}. 217 | 218 | This solution is easy to use, clean. It saves you time copying files back and forth from the virtual machine. You can simply develop in Windows using your favorite tool (IDE and test it easily under ``Linux''. It's a good solution for the purpose of this course. 219 | \end{block} 220 | \end{frame} 221 | 222 | \begin{frame}[fragile]{Aspects of Linux: Users} 223 | \vspace{-0.12in} 224 | \begin{description}[Permission] 225 | \small 226 | \item[MultiUser] Multiple person can operate the system at once. 227 | \item[Group] Each User belongs to one or more groups 228 | \item[Home Dir] Each user has his/her own directory under \texttt{/home} 229 | \item[$\sim$/] Shorthand for home directory. This one is user specific. 230 | \item[Premission] Owner/Group/Other Read/Write/Execute Flags 231 | \item[root] A special super user \texttt{root} overrides all security 232 | \item[su] Command that starts a temporary shell as \texttt{root} 233 | \item[sudo] A command that temporarily grant superuser privilege to current user. Namely, ``execute the following command as `root`". 234 | \end{description} 235 | \small{The Miranda warning of \texttt{sudo}:} 236 | \begin{minted}[fontsize=\footnotesize]{text} 237 | We trust you have received the usual lecture from the local 238 | System Administrator. It usually boils down to these three things: 239 | #1) Respect the privacy of others. 240 | #2) Think before you type. 241 | #3) With great power comes great responsibility. 242 | root's password: 243 | \end{minted} 244 | \end{frame} 245 | 246 | \begin{frame}{Aspects of Linux: Filesystem} 247 | \begin{block}{Filesystem is an abstraction of storage} 248 | That's right, abstraction again. Filesystem hides the physical storage schema of your files. Instead it should reflect how your files are logically organized. 249 | \end{block} 250 | \begin{block}{Linux Filesystem} 251 | In Linux files are organized in a tree-like structure. 252 | \begin{figure} 253 | \vspace{-0.2in} 254 | \centering 255 | \includegraphics[scale=0.5]{fig/rc2_linuxfs} 256 | \end{figure} 257 | \end{block} 258 | \end{frame} 259 | 260 | \begin{frame}{Aspects of Linux: Filesystem} 261 | \framesubtitle{Caveats for the names} 262 | 263 | \begin{block}{A word from Ken Thompson} 264 | \begin{quote} 265 | Ken Thompson was once asked what he would do differently if he were redesigning the UNIX system. His reply: "I'd spell creat with an e." 266 | \end{quote} 267 | \end{block} 268 | 269 | \vspace{-0.15in} 270 | \begin{columns} 271 | \column{.5\textwidth} 272 | \begin{description}[/boot] 273 | \item[/bin] \textbf{Bin}aries 274 | \item[/dev] \textbf{Dev}ices 275 | \item[/boot] \textbf{Boot}strap 276 | \item[/sbin] \textbf{S}ecure \textbf{bin}aries 277 | \end{description} 278 | \column{.5\textwidth} 279 | \begin{description}[/home] 280 | \item[/mnt] \textbf{M}ou\textbf{nt}ed filesystem 281 | \item[/etc] Configuration files 282 | \item[/usr] \textbf{U}nix \textbf{s}ystem \textbf{r}esources 283 | \item[/home] Places for the user's files 284 | \end{description} 285 | \end{columns} 286 | 287 | \vspace{0.1in} \tiny{More at https://wiki.debian.org/FilesystemHierarchyStandar} 288 | \end{frame} 289 | 290 | \begin{frame}{Aspects of Linux: Shell} 291 | 292 | \begin{block}{CLI and Shell} 293 | \textbf{C}ommand \textbf{L}ine \textbf{I}nterface is fast, consumes minimum resources and effective. \textbf{G}raphical \textbf{U}ser \textbf{I}nterface comes with a much larger cost. 294 | 295 | Management tasks are generally easier on CLI (think about coding!). 296 | 297 | The program that interprets user commands and provides feedbacks is called a \textit{Shell}. When you login to the computer, the shell runs automatically. You interact with the computer through the shell. 298 | \end{block} 299 | 300 | \begin{block}{Differenct choices of shell} 301 | The ``standard" one on most linux is \texttt{bash}, as in ``\textbf{B}ourne's \textbf{A}gain \textbf{Sh}ell". But choices like \texttt{zsh}, \texttt{fish}, \texttt{csh} are much more easier to use (cooler). Checkout the ``oh-my-zsh" project on GitHub if you are interested. 302 | \end{block} 303 | \end{frame} 304 | 305 | \begin{frame}{Aspects of Linux: Shell} 306 | \framesubtitle{The working directory} 307 | How does \texttt{fopen("test.txt")} work? I mean, how does the computer know where to find \texttt{text.txt}? 308 | 309 | Each program is associated with a special directory called ``working directory". Normally this is the directory where you execute the program. (Not where the program is!). 310 | 311 | \begin{block}{Related commands} 312 | \small 313 | \begin{description}[pwd] 314 | \item[pwd] \textbf{P}rint \textbf{w}orking \textbf{d}irectory 315 | \item[cd] \textbf{C}hange \textbf{d}irectory. Each directory has 2 very special ``sub-directory". ``\textbf{./}" and ``\textbf{../}". They are logically sub-directory. Meaning you can do \texttt{cd /home/john/./} and \texttt{cd /home/john/../}, but the in fact, the first command takes you to \texttt{/home/john/} and the second one takes you to \texttt{/home/}. 316 | 317 | ``\texttt{cd ./}" keeps where you are and ``\texttt{cd ../}"" takes you 1 level up. 318 | \end{description} 319 | 320 | 321 | \end{block} 322 | \end{frame} 323 | 324 | \begin{frame}[fragile]{Aspects of Linux: Shell} 325 | \framesubtitle{Executing programs} 326 | The general syntax is 327 | \begin{minted}{bash} 328 | executable_file arg1 arg2 arg3 ... 329 | \end{minted} 330 | Conventions are:\\ 331 | 1) arguments begin with \texttt{-} are called "switches" or "options" \\ 332 | 2) one dash (one \texttt{-}) are called short switches, e.g. \texttt{-l}, \texttt{-a}\\ 333 | 3) short switch always uses single letter to specify. Case / lower letters can have very different meanings! Be very careful. 334 | 3) multiple short switches can often be specified at once. e.g. \texttt{ls -al}\\ 335 | 4) two dashes (one \texttt{-}) are called long switches, e.g. \texttt{--all}, \texttt{--mode=linear}. Usually long switches use whole words other than acronyms.\\ 336 | 5) \textbf{THERE ARE OUTLIERS!}. Unfortunately \texttt{gcc} and \texttt{g++} are two of these naughty boys. 337 | \end{frame} 338 | 339 | \begin{frame}{Aspects of Linux: Shell} 340 | \framesubtitle{Useful commands} 341 | \begin{description}[mkdir] 342 | \item[ls] \textbf{L}i\textbf{s}t files \& folders under a directory. This command takes zero or more arguments. If the argument is a directory, list that dir. If the argument is a file, show information of that specific file. If no arguments are given, list working directory. 343 | \begin{description}[-a] 344 | \small 345 | \item[-a] List hidden files as well. Leading dot means ``hidden". 346 | \item[-l] Use \textbf{l}ong format. Each line for a single file. 347 | \end{description} 348 | \item[mkdir] \textbf{M}a\textbf{k}e \textbf{dir}ectory, self-explanatory. 349 | \item[rm] \textbf{R}e\textbf{m}ove files / directory. It is \textbf{extremely dangerous} to run \texttt{rm} with administrative privilege! See the bumblebee accident. \small{https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123} 350 | \begin{description}[-a] 351 | \small 352 | \item[-r] Deletes files/folders recursively. Folders requires this option. 353 | \item[-f] Force remove. Ignores warnings. 354 | \end{description} 355 | \item[rmdir] \textbf{R}e\textbf{m}ove \textbf{dir}ectory, only \textbf{empty} ones can be removed this way. 356 | \end{description} 357 | 358 | \end{frame} 359 | 360 | \begin{frame}{Aspects of Linux: Shell} 361 | \framesubtitle{Useful commands, Cont'd} 362 | \begin{description}[mkdir] 363 | \item[touch] Designed to change the time stamp of file. Commonly used to create an empty file. 364 | \item[cp] \textbf{C}o\textbf{p}y files/folder. Takes 2 arguments \texttt{source} and \texttt{dest}. Be very careful if both \texttt{source} and \texttt{dest} are both existing folders. Try it yourself! 365 | \begin{description}[-] 366 | \small 367 | \item[-r] Copy files/folders recursively. Folders requires this option. 368 | \end{description} 369 | \item[mv] \textbf{M}o\textbf{v}e files / directory. Takes 2 arguments \texttt{source} and \texttt{dest}. If \texttt{source} and \texttt{dest} is the same location, this command essentially does a rename. Pay attention to the situation where both arguments are already existed. 370 | \item[cat]<2-> Con\textbf{cat}enate files. Takes multiple arguments and print their content one by one to \texttt{stdout}. When there is just one argument, it essentially displays the content. 371 | \end{description} 372 | \end{frame} 373 | 374 | \begin{frame}{Aspects of Linux: Shell} 375 | \framesubtitle{CLI Utilities} 376 | \begin{description}[vi/vim] 377 | \item[nano] Command line file editor. 378 | \item[diff] Compare the \textbf{diff}erence of two files. 379 | \begin{description}[-] 380 | \small 381 | \item[-y] A side by side view, try it yourself. 382 | \item[-w] Ignore white spaces. 383 | \end{description} 384 | \item[less] Prints the content from its \texttt{stdin} in a readable way. 385 | \item[vi] Advanced text editor 386 | \item[vim] \textbf{v}i \textbf{im}proved, both \texttt{vi} and \texttt{vim} can be exited by first press \texttt{ESC} and type ``\texttt{:q!}". You should know this in case your ``friend" opens a \texttt{vi} window when you are away, so you won't get stuck inside. 387 | \item[grep] Filters input and extracts lines that contains specific content. Very useful in debugging programs. 388 | \item[echo] Prints its arguments to \texttt{stdout}. 389 | \end{description} 390 | 391 | \end{frame} 392 | 393 | \begin{frame}{Aspects of Linux: Shell} 394 | \framesubtitle{IO Redirection} 395 | When you are reading \texttt{cin} or writing to \texttt{cout}, you are essentially read/writing 2 special files. Again, abstraction, right? 396 | 397 | It is possible to ``switch" these two ``virtual files" with real files before the actual execution of the program. This is called IO ``redirection". 398 | 399 | There are 4 most common redirections: 400 | 401 | \begin{description}[\texttt{exec >> output}] 402 | \item[\texttt{exec < input}] Use \texttt{input} as \texttt{stdin} of \texttt{exec} 403 | \item[\texttt{exec > output}] Write the \texttt{stdout} of \texttt{exec} into \texttt{output}. Note this command always truncates the file. File will be created if it is not already there. 404 | \item[\texttt{exec >> output}] Similar to \texttt{>}, but it appends to \texttt{ouput}. 405 | \item[\texttt{prog1 | prog2}] Called a ``pipe". Connects the \texttt{stdout} of \texttt{prog1} to \texttt{stdin} of \texttt{prog2} 406 | \end{description} 407 | \end{frame} 408 | 409 | \begin{frame}{Aspects of Linux: Shell} 410 | \begin{block}{Globbing} 411 | Sometimes you don't care about one file, you care about \textbf{all} files. You can use \texttt{*} to represent any string in command arguments. This is called ``globbing" and the \texttt{*} is called a wildcard. 412 | 413 | \begin{itemize} 414 | \item List every \texttt{.cpp} file in home dir: \texttt{\$ ls -al $\sim$/*.cpp} 415 | \item Delete everything in \texttt{/temp}: \texttt{\$ rm -rf /temp/*} 416 | \item Combine all \texttt{.h} into one: \texttt{\$ cat *.h > combined.h} 417 | \end{itemize} 418 | \end{block} 419 | 420 | \begin{block}{Looking for help} 421 | The ``goto" location for help in Linux is the \texttt{man} command. This is a short hand of ``\textbf{man}ual". 422 | \begin{itemize} 423 | \item Find out information about ``vi": \texttt{\$ man vi} 424 | \item Confused about \texttt{cp}: \texttt{\$ man cp} 425 | \end{itemize} 426 | \end{block} 427 | \end{frame} 428 | 429 | \begin{frame}[fragile]{Example of shell commands} 430 | \framesubtitle{Setup} 431 | The following program \texttt{rc2xm} reads from it's standard input line by line and prepends \texttt{xm} at the beginning and print it out. 432 | \inputminted{c++}{code/rc2xm/xm.cpp} 433 | We prepare an input file \texttt{xm.in} with the following content: 434 | 435 | \small{\texttt{xd$\hookleftarrow$ cg$\hookleftarrow$ hss $\hookleftarrow$ xtt $\hookleftarrow$ qs $\hookleftarrow$ jcc $\hookleftarrow$ xdtql $\hookleftarrow$ zdnxd $\hookleftarrow$}} 436 | 437 | We use $\hookleftarrow$ to represent new-line to save space on slides. 438 | \end{frame} 439 | 440 | \begin{frame}{Example of shell commands} 441 | \framesubtitle{Examples} 442 | For each of the following commands what is it's effect? What is the final output? 443 | \vspace{-.2in} 444 | \begin{columns} 445 | \column{.5\textwidth} 446 | \begin{block}{The commands} 447 | \texttt{\$ cat xm.in}\\ 448 | \texttt{\$ cat xm.in > xm3.in}\\ 449 | \texttt{\$ ./rc2xm < xm.in}\\ 450 | \texttt{\$ ./rc2xm < xm.in > xm.out}\\ 451 | \texttt{\$ cat xm* > xm2.in}\\ 452 | \texttt{\$ cat xm*.in >> xm.out}\\ 453 | \texttt{\$ cat xm* | ./rc2xm > out}\\ 454 | \texttt{\$ ./rc2xm (&a); // C++11 style cast 48 | *p = 20; cout << a; // Will this output 20? 49 | \end{minted} 50 | 51 | Well this is actually UB. \texttt{const} is not a guarantee of immutability, it is an \textbf{intention}. It asks the compiler to look out for you, if you know you shouldn't change something. 52 | \end{frame} 53 | 54 | \begin{frame}{\texttt{const} and pointers} 55 | We now combine the previous discussions. 56 | 57 | \begin{description}[\texttt{int *(const p)}] 58 | \item[\texttt{const int *p}] \texttt{*p} is of type \texttt{const int}, thus changing \texttt{*p} is illegal. However this declaration does \textbf{not} say anything about \texttt{p}, thus changing \texttt{p} is possible. 59 | 60 | This is called \textit{pointer-to-const}. 61 | 62 | \item[\texttt{int *const p}] Equivalent to \texttt{int *(const p)}. 63 | \item[\texttt{int *(const p)}] This declaration essentially says if you dereference \texttt{const p}, you will get \texttt{int}. Since \texttt{int} is not quantified by \texttt{const}, you can change \texttt{*p}. However, the pointer itself, is modified by \texttt{const}, so you can change \texttt{p}. 64 | 65 | This is called \textit{const-pointer}. 66 | \end{description} 67 | 68 | Naturally you could have \texttt{const int *(const p)}. This declaration basically says both the pointer \texttt{p} itself and the dereferenced object (\texttt{const int}) cannot be changed. 69 | \end{frame} 70 | 71 | \begin{frame}{\texttt{const} and reference} 72 | Recall that \textbf{references cannot be rebind once initialized}. The following definitions are equivalent. They are all \textit{const references}. 73 | 74 | \begin{itemize} 75 | \item \texttt{const int\& iref} 76 | \item \texttt{(const int)\& iref} 77 | \item \texttt{int\& (const iref)} 78 | \item \texttt{const int\& (const iref)} 79 | \end{itemize} 80 | 81 | The second one makes the most sense, although the first one is the most commonly used. 82 | 83 | The second one essentially says,\texttt{iref} is a reference, or an alias to a memory region, that is protected by the \texttt{const} modifier. 84 | \end{frame} 85 | 86 | \begin{frame}[fragile]{\texttt{const} reference and argument passing} 87 | There is something special about const references: 88 | \begin{center} 89 | \structure{Const reference are allowed to be bind to right values,\\ while normal references are not allowed to.} 90 | \end{center} 91 | Normally if a const reference is bind to a right value, the const reference is no difference to a simple const. 92 | \begin{minted}{c++} 93 | int a=5; const int& r=a+1; const int c=a+1; 94 | \end{minted} 95 | In above example practically there is no difference between \texttt{r} and \texttt{c}. 96 | 97 | But when you pass arguments through const references, things become a little bit different. 98 | \begin{minted}{c++} 99 | int foo(const ReallySuperLargeStruct& s); 100 | \end{minted} 101 | \vspace{-0.05in} 102 | \begin{itemize} 103 | \item We are passing by reference, this avoids copying. 104 | \item \texttt{const} enforces immutability. 105 | \item \texttt{rval}s can be passed directly into it (unlike pointers). 106 | \end{itemize} 107 | \end{frame} 108 | 109 | \begin{frame}[fragile]{Example} 110 | \begin{columns} 111 | \column{.5\textwidth} 112 | \begin{minted}{c++} 113 | int foo(int); int bar(int&); 114 | int baz(const int&); 115 | 116 | int q = 10; int& rq = q; 117 | const int& crq = q; 118 | int* pq = &q; 119 | const int* cpq = &q; 120 | 121 | void foobar() { 122 | crq = 5; // Error! 123 | *cpq = 20; // Error! 124 | q = 30; cout << crq; // 30 125 | *pq = 4; cout << *cpq // 4 126 | } 127 | \end{minted} 128 | \column{.5\textwidth} 129 | \begin{minted}{c++} 130 | int bazbok() { 131 | baz(q); baz(20); // OK 132 | baz(*pq); baz(rq); // OK 133 | 134 | bar(q); bar(*pq); // OK 135 | bar(10); // ERROR 136 | bar(*cpq); // ERROR 137 | bar(crq) // ERROR 138 | } 139 | \end{minted} 140 | \end{columns} 141 | \end{frame} 142 | 143 | \begin{frame}[fragile]{\texttt{const} propagation and type coercion} 144 | 145 | \begin{block}{Type coercion and type compatibility} 146 | You should be very familiar with types now. Types defines different kinds of things. Some of those things are \textit{compatible}, meaning one could be transformed into another implicitly. But sometimes you need to explicitly \textit{cast} them, or coerce them into another type. 147 | 148 | \begin{minted}{c++} 149 | int x = 20; long int y = 30; char* p = "hello"; 150 | y = x; /* OK */ x = y; // Compiler warning 151 | int x = p; // Incompatible, compile error 152 | \end{minted} 153 | \end{block} 154 | 155 | A remark is that most of the things are incompatible, simply because these different type are different from the hardware point of view. Pointers are addresses, but int are number. \texttt{long int} occupies more space than \texttt{int} etc. 156 | 157 | \end{frame} 158 | 159 | \begin{frame}[fragile]{\texttt{const} propagation and type coercion} 160 | \framesubtitle{\texttt{const} modifier introduce incompatibility} 161 | 162 | The subtitle is summarized into the following rules: 163 | 164 | \begin{itemize} 165 | \item \texttt{const type\&} to \texttt{type\&} is \textbf{incompatible}. 166 | \item \texttt{const type*} to \texttt{type*} is incompatible. 167 | \item \texttt{type\&} to \texttt{const type\&} is \textbf{compatible}. 168 | \item \texttt{type*} to \texttt{const type*} is compatible. 169 | \end{itemize} 170 | Example: 171 | \begin{minted}{C++} 172 | int foo(int& x); int bar(int* px); int cfoo(const int& x); 173 | void baz() { 174 | const int *q = nullptr; int *p = q; //Compile error 175 | const int& r = 10; foo(r); //Compile error 176 | cfoo(*p); cfoo(*q); cfoo(r); // All OK 177 | } 178 | \end{minted} 179 | 180 | \end{frame} 181 | 182 | 183 | 184 | \begin{frame}[fragile]{\texttt{const} propagation and type coercion} 185 | \framesubtitle{\texttt{const} progagation} 186 | Further more, \texttt{const} modifier attaches extra constrain when trying to take address or dereference / reference things. 187 | 188 | \begin{itemize} 189 | \item Take address of the \texttt{const} references gives pointer-to-const. 190 | \item Dereferences pointer-to-const give const references. 191 | \end{itemize} 192 | Example: 193 | \begin{minted}{C++} 194 | int foo(int& x); int bar(int* px); int cfoo(const int& x); 195 | void baz() { 196 | const int q = nullptr; int *p = &q; //Compile error 197 | foo(q); bar(&q) //Compile error 198 | const int& r = q; foo(r); bar(&r); // Compile errer 199 | } 200 | \end{minted} 201 | This creates an important feature of C++ \texttt{const}ness: 202 | 203 | \structure{You either do it in full scale, or not at all}. 204 | \end{frame} 205 | 206 | \begin{frame}{\texttt{const} compatibility in terms of abstraction} 207 | \small 208 | Again I hope you could see something bigger. These rules are unlike those mentioned earlier. The compiler probably use the same representation for \texttt{type*} and\texttt{const type*}. 209 | 210 | They are different, because they follow different abstraction. The abstraction for \texttt{type*} supports modification, or it is supported to appear on the left hand side of the assignment operator, while the abstraction of \texttt{const type*} does not. 211 | 212 | This point of view also explains the propagation rules. The type system must be designed in a coherent way. If an object doesn't support modification, changing the reference to pointer won't suddenly equip it with modification. The abstraction must be maintained between operations. 213 | 214 | This gives a very first look over the abstraction point of view of the concept ``datatype". Now we see that datatype not just the memory layout of objects, but more about abstraction, operations that the type supports. 215 | 216 | \end{frame} 217 | 218 | 219 | 220 | \begin{frame}{Functions Pointers: Why Pointers?} 221 | 222 | \structure{The Von Neumann View of functions} 223 | 224 | Functions are code, and code when compiled are simply binary number, i.e. data. The action of calling a function is simply pumping these binary numbers into the CPU (after you take VE370 you would find it's actually the other way around). 225 | 226 | \begin{itemize} 227 | \item Functions are just a bunch of numbers in the memory 228 | \item We could refer to the function by refering to the numbers 229 | \item These numbers has an \textit{address} (think of arrays) 230 | \item We could use that address to refer to the function 231 | \end{itemize} 232 | 233 | Variable that stores the address of functions are called \textit{function pointers}. By passing them around we could pass functions into functions, return them from functions, and assign them to variables. 234 | \end{frame} 235 | 236 | \begin{frame}{Functions Pointers: Type} 237 | But there is one question, what is the type of them? 238 | 239 | Well by our previous understanding dereferencing a function pointer should give us a function, just like dereferencing \texttt{int*} gives us \texttt{int}. We would like to do a comparison: 240 | 241 | \vspace{-.2in} 242 | \begin{columns} 243 | \column[]{.5\textwidth} 244 | \begin{block}{Function decl. \texttt{foo}} 245 | \begin{itemize} 246 | \item \texttt{void foo();} 247 | \item \texttt{int foo(int x, int y);} 248 | \item \texttt{int foo(int, int);} 249 | \item \texttt{int *foo(int, char*);} 250 | \item \texttt{char* foo(int[], int);} 251 | \end{itemize} 252 | \end{block} 253 | \column[]{.6\textwidth} 254 | \begin{block}{Function pointer \texttt{bar}} 255 | \begin{itemize} 256 | \item \texttt{void (*bar)();} 257 | \item \texttt{int (*bar)(int, int);} 258 | \item \texttt{int (*bar)(int, int);} 259 | \item \texttt{int *(*bar)(int, char*);} 260 | \item \texttt{char *(*bar)(int[], int);}. 261 | \end{itemize} 262 | \end{block} 263 | \end{columns} 264 | Note \texttt{int *bar(int);} does \textbf{NOT} declare a function pointer. The grouping is \texttt{int *(bar(int))}, which is declaring a function. This is related to the operator precedence of C++. 265 | \end{frame} 266 | 267 | \begin{frame}[fragile]{Functions Pointers: Usage} 268 | \begin{block}{Assignment from functions} 269 | In fact, the identifier (name) of the functions are actually values of function pointers. 270 | \begin{minted}{c++} 271 | int max(int x, int y) { return x > y ? x : y;} 272 | int (*cmp)(int, int) = max; 273 | \end{minted} 274 | \end{block} 275 | \vspace{-0.1in} 276 | \begin{block}{Invoking a function pointer} 277 | You can invoke a function pointer by applying operator \texttt{()} to it. 278 | \begin{minted}{c++} 279 | int m = cmp(10, 20); // No need to dereference it 280 | \end{minted} 281 | \end{block} 282 | \vspace{-0.1in} 283 | \begin{block}{Invariance under \texttt{*}} 284 | Dereferencing a function pointer still gives back a function pointer. 285 | \begin{minted}{c++} 286 | int m = cmp(10, 20); // 20 287 | int n = (*cmp)(10, 20); // 20 288 | int p = (*******cmp)(10, 20) // 20 289 | \end{minted} 290 | \end{block} 291 | \end{frame} 292 | 293 | \begin{frame}[fragile]{Example} 294 | The following code implements a simple calculator. Notice how function pointer helps to clarify the code. 295 | 296 | \texttt{$-->$ code/rc4fptr/fptr.cpp} 297 | \inputminted{c++}{code/rc4fptr/fptr.cpp} 298 | \end{frame} 299 | 300 | 301 | \begin{frame}[fragile]{\texttt{typedef} storage modifier} 302 | The \textbf{typedef} keyword is actually a storage modifier (like \texttt{static}), means it goes to wherever \texttt{static} can appear. 303 | 304 | Reading a \texttt{typedef} is actually very simple: 305 | \begin{enumerate} 306 | \item Ignore \texttt{typedef} and read the line as if it is a real declaration. 307 | \item Now the ``declared" variable would have a declared type 308 | \item Finally we put back \texttt{typedef}. The variable now become an alias to the declared type. 309 | \end{enumerate} 310 | Example: 311 | \begin{minted}{c++} 312 | typedef bool (*comparator)(double, double); 313 | typedef const Comparator const_comparator; 314 | const_comparator *p = nullptr; 315 | *p = min; // Error!, p is pointer-to-const 316 | comparator cmp[] = {min, max}; // Array of function ptrs 317 | \end{minted} 318 | \end{frame} 319 | 320 | 321 | \begin{frame}[fragile]{Semantic of \texttt{typedef}} 322 | \framesubtitle{Motivation} 323 | It is now to analyze the semantic of \texttt{typedef}: not how is used, but why is it used in such way. If you go through the standard library. you would find some code like: 324 | \begin{minted}{c++} 325 | typedef unsigned int size_t; 326 | \end{minted} 327 | What's the point of doing this if when you can just use \texttt{unsigned int }? Suppose you are trying to find your name with your student ID, which is an unsigned integer: 328 | \begin{minted}{c++} 329 | string getNameByID(unsigned int student). 330 | \end{minted} 331 | This is not good, because \texttt{student} is not any \texttt{unsigned int}, it must be a student ID. You would like to emphasize on that: 332 | \begin{minted}{c++} 333 | typedef unsigned int student_id; 334 | string getNameByID(student_id id); 335 | \end{minted} 336 | \end{frame} 337 | 338 | \begin{frame}[fragile]{Semantic of \texttt{typedef}} 339 | But here comes a problem: 340 | \begin{center} 341 | \structure{\texttt{typedef} creates alias, not new types.} 342 | \end{center} 343 | This essentially says both \texttt{student\_id} and \texttt{size\_t} are both alias for \texttt{unsigned int}. They are essentially considered the same thing. 344 | 345 | The following code does not \textbf{NOT} make sense: 346 | 347 | \begin{minted}{c++} 348 | size_t numberOfApples = 20; 349 | string name = getNameByID(numberOfApples); 350 | \end{minted} 351 | 352 | but the compiler lets you do this without even a warning. Semantic of the types should prevent you from making these assignments (easily), but \texttt{typedef} breaks this promise. 353 | 354 | On the other hand, \texttt{classes} are more modern. Two \texttt{classes} with same ``composition" are considered incompatible different types.` 355 | 356 | \end{frame} 357 | 358 | \subsection{Procedure Abstraction} 359 | \begin{frame}{Abstraction and \textit{decoupling}} 360 | The motivation of all abstraction comes directly from the need for decoupling. We would like to design the software in such way, that the change in one portion of the code does not affect the others. 361 | 362 | \vspace{0.1in} 363 | But after all some degree of coupling is inevitable, conceptually we would like to limit the coupling only to the interfaces, i.e. where modules connect. 364 | 365 | \begin{columns} 366 | \column{.33\textwidth} 367 | \structure{Low coupling:} 368 | \begin{figure} 369 | \centering 370 | \includegraphics[scale=0.34]{fig/low-coupling} 371 | \end{figure} 372 | \column{.34\textwidth} 373 | \structure{High coupling:} 374 | \begin{figure} 375 | \centering 376 | \includegraphics[scale=0.35]{fig/high-coupling} 377 | \end{figure} 378 | \column{.33\textwidth} 379 | \structure{Low coupling for flexibility:} 380 | \begin{figure} 381 | \centering 382 | \includegraphics[scale=0.33]{fig/low-coupling-flex} 383 | \end{figure} 384 | \end{columns} 385 | 386 | \end{frame} 387 | 388 | \begin{frame}{Independence of variation} 389 | We some times simply refer these interfaces, or connection points, \textit{the abstraction}. Now we take a look at the \textit{implementation} side of the abstraction. 390 | 391 | If you the abstraction implementation is done right, you should find the following property of your abstraction. 392 | 393 | \begin{itemize} 394 | \item Locality. The implementation should only depend on other abstraction, not abstraction implementation. 395 | \item Substitutable. The implementation is not unique. Any implementation that obeys the abstraction should work. 396 | \end{itemize} 397 | 398 | The ultimate goal is the the only coupling point in your program should be the abstraction. \alert{So this is utterly import to always think through the abstraction before the actual implementation.} 399 | \end{frame} 400 | 401 | \begin{frame}{Elements in procedure abstraction} 402 | A common point of where modules connect is function calls. But think bigger, when you say \texttt{printf("\%d", 1)}, you are requesting a service, requesting for certain operation. This idea that programs are driven by requests for operations sums up to the idea of \textit{Procedure Abstraction}. Remember functions are just one realization of the idea of Procedure abstraction, but not the only one. 403 | 404 | We now examine how functions interact with the outside world. These things will be very important in specifying the abstraction: 405 | 406 | \begin{itemize} 407 | \item Input and it's assumption 408 | \item Expected output, and the property of the output 409 | \item Impact on the environment, or side effects. 410 | \end{itemize} 411 | \end{frame} 412 | 413 | \begin{frame}[fragile]{Specifying abstraction} 414 | Typically an abstraction is specified in the following manner: 415 | \begin{minted}{c++} 416 | int reallyUselessFoo(int& intArg, string str); 417 | // REQUIRES : intArg > 0, str != "" 418 | // MODIFIES : cout, intArg, UsefulGlobalVar 419 | // EFFECTS : do Blah blah blah and return blah blah 420 | \end{minted} 421 | \begin{itemize} 422 | \item \textit{REQUIRE} clause and the function signature specifies the input. Number of inputs are fully specified by the signature, input range can be partially specified through type. 423 | \item \textit{EFFECTS} clause and the function signature specifies the output. The expected output is partially specified by the type of the return value. It is important to note that the function name is also part of the specification, it should clearly and concisely reflect on what the function does. 424 | \item \textit{MODIFIES} clause specify side effects. 425 | \end{itemize} 426 | \end{frame} 427 | 428 | \begin{frame}[fragile]{Side effects} 429 | We have left out the term ``side effects" for now. Let's take a look at them. Think of mathematical functions, you would expect the following of them: 430 | \begin{block}{Functions are maps} 431 | Functions should return the same if provided same input: 432 | \begin{minted}{c++} 433 | (fun(x) == fun(x)) == true 434 | \end{minted} 435 | 436 | \end{block} 437 | \begin{block}{Functions are stateless} 438 | Programs should behave the same for the following two lines 439 | \begin{minted}{c++} 440 | int x = foo(y); int z = bar(x, x); 441 | int z = bar(foo(y), foo(y)); 442 | \end{minted} 443 | 444 | The following 2 lines should also be equivalent. 445 | \begin{minted}{c++} 446 | int x = foo(y); 447 | int x = foo(y); int x = foo(y); 448 | \end{minted} 449 | 450 | \end{block} 451 | \end{frame} 452 | 453 | \begin{frame}[fragile]{Side effects} 454 | It is our intuition that all these assertions should be true. But unfortunately we can break them. Once we break these intuitions it will be very hard for programmers to keep track of program. 455 | 456 | \structure{Through global/static variables} 457 | \begin{minted}{c++} 458 | int x = 3; int foo(int y) {return y + x++;} 459 | int bar(int y) {static int x = 0; return y + x++;} 460 | \end{minted} 461 | \structure{Through modifying arguments} 462 | \begin{minted}{c++} 463 | int x = 3; int foo(int& x) {return ++x;} 464 | \end{minted} 465 | \structure{Involving IO} 466 | \begin{minted}{c++} 467 | int x = 3; int foo(int x) {cout << "Hello"; return x;} 468 | \end{minted} 469 | 470 | Functions are suppose to be maps, converting one value to another. In all these values the function does something else. They modify something that does not belong to them. 471 | 472 | These behaviors are called \textit{side effects}. 473 | \end{frame} 474 | 475 | \begin{frame}[fragile]{Function signature is important} 476 | A huge amount of information is provided in the function signature. In fact we believe the following should be true: 477 | \begin{center} 478 | \structure{Good code should be self explanatory.\\ Good abstraction should be self documenting.} 479 | \end{center} 480 | It means you should be able to guess the abstraction's usage, just by looking at it's function signature. Compare the following: 481 | \begin{minted}{c++} 482 | void dwcl(double a, double b, double c); 483 | void drawCircle(Point p, double radius); 484 | \end{minted} 485 | It is generally considered good to 486 | \begin{itemize} 487 | \item Avoid introducing too much arguments. Pack arguments that are related into structure / classes. 488 | \item Avoid using acronyms in function names. You have very good editors that provides extensive support for auto-completion. 489 | \end{itemize} 490 | \end{frame} 491 | 492 | \begin{frame}[fragile]{Leaky Abstractions} 493 | Officially our discussion of procedural abstraction has ended. But I would like to make a few comments. We would like to ask: 494 | \begin{center} 495 | \structure{Are there PERFECT abstractions?} 496 | \end{center} 497 | Perfect abstractions are abstractions that completely hides information about the implementation, a complete black box. People often need a perfect abstraction, e.g. for cryptography. 498 | 499 | Compare the following, assume both arguments are positive: 500 | \begin{minted}{c++} 501 | int mul1(int x, int y) {return x * y;} 502 | int mul2(int x, int y) {return x==0 ? 0 : y+mul2(x-1,y));} 503 | \end{minted} 504 | Both implementation are correct. Can we differentiate them? The second one is significantly slower than the first one. If we provide a really large input, we would be able to differentiate them by the runtime! We say we have a \textit{leaky abstraction} at our hand. 505 | \end{frame} 506 | 507 | \begin{frame}[fragile]{the Law of Leaky Abstractions} 508 | the Law of Leaky Abstractions (Spolsky, 2002) says: 509 | \begin{quotation} 510 | \structure{All non-trivial abstractions, to some degree, are leaky.} 511 | \end{quotation} 512 | How is this important? By now should be clear that the proper functionality of software (and computer system) often depends on the reliability of abstraction. But at some point, the abstraction will break. Examples: 513 | \begin{itemize} 514 | \item In C/C++ iterating through large 2D array horizontally is significantly faster than vertically. 515 | \item \textit{L3-cache side channel attack}. Takes advantage a leaky abstraction inside the CPU to steal your ``password". 516 | \end{itemize} 517 | As a measure to counter this problem you sometimes see the standard not only specify a function's behavior, but also it's runtime (in terms of time complexity). 518 | \end{frame} 519 | 520 | \begin{frame}{Enforcing Abstraction in C++} 521 | Another very interesting thing here is what happens if you breaks the abstraction? How abstraction is enforced in C++? 522 | \begin{itemize} 523 | \item Input number and types are protected by the type system. 524 | \item Input But the properties of input (even?) are left unsaid. 525 | \item Output type and number (guarantees there exists one output if needed) is protected by the type system. 526 | \item Whether output fits the expected behavior is unchecked. 527 | \item Side effects are completely unchecked. 528 | \end{itemize} 529 | As you can see many things are left unchecked! Most of the checking is done by the type system. In fact, the type system plays a really important role in programming language. The fact that C/C++ is a statically typed language is greatly complimented and provides much help in writing correct programs. 530 | \end{frame} 531 | 532 | \begin{frame}{Enforcing Abstraction: How far can we go?} 533 | Here I list a couple of other language's idea. You may or may not know that language, but that's completely alright. 534 | \begin{description}[Matlab/Python] 535 | \item[Matlab/Python] Dynamically typed. The type of arguments are not declared and only known at runtime. 536 | \item[Bash] Scripting language used by shell. Not even typed. Not even check the arguments of function called. Basically zero protection. 537 | \item[Haskell] A language that is statically typed. The type system is so powerful that it requires the programmer to declare not only the inputs, but also the ``side effects" (and checks them). 538 | \item[COQ] A language that goes to the extreme. It not only asks the programmer to declare everything, it even requires the program to provide a proof (and checks the proof) of correctness. 539 | \end{description} 540 | \end{frame} --------------------------------------------------------------------------------