CPSC 327 Final

¡Supera tus tareas y exámenes ahora con Quizwiz!

Because of the global interpreter lock in CPython, we should... A. use processes for I/O bound programs and threads for CPU bound programs B. always use threads C. avoid concurrency because Python does now allow it D. always use processes E. use threads for I/O bound programs and processes for CPU bound programs

E

True or False? Const methods cannot be used by non-const objects.

False All objects (const and non-const) can call const methods

True or False? A Thread can exist outside of a process.

False Every thread is part of a process.

True or False? The default destructor will delete all objects pointed to by instance variables.

False One should define their own destructor to free memory that is dynamically-allocated

True or False? In the memento pattern, the caretaker reads instance variables from the originator to create the memento objects.

False The caretaker does not access the state of the originator object

True or False? Like a constructor, a class cannot define more than one factory method.

False This is the abstract factory pattern (has more than one factory method)

True or False? The refused bequest code smell is when a developer refuses to use primitive types in place of classes.

False This is the primitive obsession code smell. The refused bequest code smell occurs when a child class does not use code from the parent class.

True or False? In the XmlParser example we needed to add the singleton code to each state class separately so that each would have its own singleton instance.

False • We define the class method get_instance in the abstract base class, which returns the singleton instance • Since this method is then inherited by each of the state classes, calling get_instance on each state subclass returns the singleton as an instance of the subclass • This same behavior can be achieved by using the constructor __new__ **This is a very important example, review it

Code Smells - Couplers

Feature envy: • Method uses data from another object more than its own • Solution: move the method to the other class Inappropriate intimacy: • A method needs private data from another class • Solution: move the method or delegate to another method Message chains: • Of the form obj.method1().method2().method3() • Solution: delegate work to a single method Middle man: • A class that does nothing other than delegate (adapter, facade patterns)

What does this line return? (x for x in [1,2,3,4])

Generator

Code Smells - Bloaters

Long method/large class: • Code tries to do too much • Solution: extract into multiple methods/classes Primitive obsession: • Using primitive data types too much makes code inflexible to future changes (ex. store phone number, cash amount as an integer) • Solution: replace with small objects Long parameter list: • Too many arguments make calls hard to read • Solution: pass in objects that bundle related data

True or False: State transitions can be handled in either the context class or the state classes.

True

True or False? A command object can defer execution of some action.

True

True or False? An observer can be removed at runtime.

True

True or False? Decorators, Adapters, and Facades are all types of Wrappers.

True

True or False? Queues from the multiprocessing library and both thread and process safe.

True

True or False? The flyweight pattern trades complexity for memory savings.

True

True or False? The iterator pattern is built into Python's for loops.

True

True or False? The yield keyword causes a function to return a Generator object.

True

True or False? pool.map(...) can be used to replace a large for loop with many independent tasks

True

True or False? super is not a built in keyword in C++.

True

True or False? Threads and processes may run in an unpredictable order.

True The operating system (OS) schedules threads for processing on its cores.

True or False? The code below could be a valid method signature. const int* const foo(const int* const bar) const;

True This is a const method that takes a const pointer to a const int and returns a const pointer to a const int

What code replaces XXXX in this example? def log_calls(func): def wrapper(*args, **kwargs): now = time.time() print("Calling {0} with {1} and {2}".format( func.__name__, args, kwargs)) return_value = XXXX print( "Executed {0} in {1}ms".format( func.__name__, time.time() - now)) return return_value return wrapper Which of the following are ways to decorate a function foo() with the log_calls decorator above? A. @log_calls def foo(): B. def foo(log_calls): C. log_calls(foo()) D. foo = log_calls(foo) E. @log_calls(foo)

func(*args, **kwargs) and A, D • This code is tricky to understand • log_calls(foo) returns a function which calls foo with any arguments passed in (*args, **kwargs)

C++ visibility: public, protected, private

public: • accessible to everyone protected: • accessible to subclasses • accessible to friends private: • default for class • only accessible from objects of this class i.e. not inherited by subclasses Ex. class Circle { double radius; }; int main() { Circle c; c.radius = 5; } ERROR: In function 'int main()': 11:16: error: 'double Circle::radius' is private double radius; ^ 31:9: error: within this context obj.radius = 5;

What are the four categories of design patterns?

(1) Creational Ways to manage the creation of objects (2) Structural Organizing classes and objects to provide new functionality (3) Behavioral Manage communication between objects (4) Concurrency Address challenges in multi-threading/multi-processing

What will the above code print? #include <iostream> using namespace std; int main () { int a = 5; int* b = &a; int*& c = b; (*c) = 10; cout << a << endl; return 0; }

10 Since c is a reference to an int*, then 'c' is an int*; thereafter, we see that '*c' is an int.

Which of these code segments is correct? (1) class Dummy { int x; Dummy(int x){ this.x = x; } }; (2) class Dummy { int x; Dummy(int x){ this->x = x; } };

2 'this' is a pointer to the object instance

What does this code print? lst = [1,2,3,4,5] it1 = iter(lst) it2 = iter(lst) next(it2) next(it1) next(it1) next(it2) next(it1) print(next(it1))

4 The iterator iterates to the fourth element (index 3)

A potential solution to parallel inheritance hierarchies could be... A. moving functionality into one hierarchy B. introducing null objects C. using an adapter pattern D. avoiding inheritance altogether

A

In Python, how do you know when an iterator has finished iterating? A. calling __next__ raises a StopIteration exception B. calling __next__ returns None C. calling __next__ returns False D. calling __done__ returns True

A

What is the difference between these two lines of code? (1) Person* tim = new Person("Tim"); (2) Person* tim = (Person*)malloc(sizeof(Person)); A. The second one does not call the constructor B. The second one will not compile in either C or C++ C. The second one allocates memory on the heap while the first one uses the stack D. The second one will only compile in C, but not C++

A new calls both malloc as well as the object's constructor

Instantiating objects in C++

Allocating memory on the stack: Person tim; Person tim("Tim"); Allocating memory on the heap: • new is a keyword in C++ that first allocates memory for an object on the heap and then calls its constructor • We can also call delete on an object pointer • delete first calls that object's destructor and thereafter frees its memory from the heap Ex. Person* tim = new Person("Tim"); delete tim;

In the State pattern which of these could be converted to singletons? A. User B. States C. Context D. Parser

B

Which of the following was not a suggestion for when to refactor? A. During a code review B. 5 line rule C. When fixing a bug D. Rule of 3 E. When adding a feature

B

When is the initializer list preferred over initializing in the constructor body? A. When the constructor is not overloaded B. When initializing an instance variable that is another object C. When there are many instance variables to set up

B If initializing an instance variable that is another object in the constructor body, then that object's constructor will be called twice

In the state pattern, the states are represented by... A. a string attribute in the context object B. state objects C. a transition table

B In the state pattern, each individual state is represented as a class inheriting from an ABC.

In which of the following cases would a Singleton be most problematic? A. configuration object B. logging object C. objects with mutable state D. objects with no state

C

Speculative generality is a... A. Bloater B. Change preventer C. Dispensable D. OOP abuser

C

A decorator must: A. hold a reference to the original subject B. not be used more than once on the same object C. maintain the same public interface as the original subject D. be defined using the @decorator syntax

C A: A decorator holds a reference to either the original subject or another decorator B: Decorator can be used any number of times D: Decorators can be either static or dynamic

Which of the following is not an advantage of decorators over subclasses? A. Decorators can be layered in different combinations B. New functionality can be added to an object at runtime C. Decorators do not involve writing new classes

C One must define new concrete decorator classes

Python getters and setters

Can define a getter and setter together using a property property(fget=None, fset=None, fdel=None, doc=None) class Person: def __init__(self, name): self._name = name def get_name(self): print('Getting name') return self._name def set_name(self, value): print('Setting name to ' + value) self._name = value def name = property(get_name, set_name) Or can define getters and setters separately using property decorators: @property def age(self): print("getter method called") return self._age @age.setter def age(self, a): if(a < 18): raise ValueError("Sorry you age is below eligibility criteria") print("setter method called") self._age = a mark = Geeks() # calls age setter mark.age = 19 # calls age getter print(mark.age)

Code Smells - Dispensables

Comments: • Too many • Code is incomprehensible without them • Solution: good class/method names can make OOP code self-documenting Duplicate code Lazy class: • Doesn't do enough to justify the added complexity Data class Dead code: • Variable, parameter, method, or class is no longer used Speculative generality: • Unused code is created prematurely

In the auction example, the auctioneer is... A. an observer B. a decorator C. a strategy D. the subject

D

What is the difference between structs and classes? A. structs cannot inherit from other structs B. structs cannot have methods C. structs are stored on the stack and classes are stored on the heap D. default visibility is public for structs and private for classes

D

Which of the following operators cannot be overloaded? A. [] B. + C. new D. sizeof E. -> F. == G. =

D

Although the purpose and usage of these two patterns differs, which of design pattern is structurally most similar to the composite pattern based on the UML diagrams?

Decorator pattern

Code Smells - Change Preventers

Divergent changes/Shotgun surgery: • Often a result of copy/pasting code • Making a change to one method forces you to adjust many other methods Parallel inheritance hierarchies: • Occurs when you subclass one class and find that it needs a corresponding subclass for another [parent] class • Solution: move functionality into one hierarchy

True or False? A subject can have only one observer attached to it.

False

True or False? The adapter pattern cannot be used to change the number of arguments to a method.

False

True or False? When writing code with multiple processes, the child processes share all the variables stored in memory.

False

In Python, all objects are instantiated on the ______.

Heap The stack stores variable references to those objects

Statically versus dynamically-typed languages

In statically-typed languages, the type of an object is determined at compile-time; in dynamically-typed languages, types are checked at runtime • C++ is a statically-typed language, Python is a dynamically-typed language

Differences between Python and C++

Memory Management: C++ has manual memory management, Python has automatic garbage collection Constants: C++ has constants (variables, classes, methods), Python does not Privacy: C++ has public, protected, private attributes and methods, Python does not Running Programs: C++ files are compiled to platform-specific binary code, Python code is run as input to an interpreter (compiled versus interpreted languages)

Code Smells - OOP Abuse

Switch statements (long if-elif-else statements in Python): • Solution: use polymorphic objects instead Temporary instance variables: • Instance variables that aren't always needed • Solution: group these variables into their own classes; rather than checking if the object exists, define a null object that has some default behavior Refused bequest: • Code from parent class is unused in child classes • Solution: replace inheritance with composition Alternative classes with different interfaces: • Solution: identify the common denominator, combine into a single class

Virtual functions in C++

Virtual function: virtual void myfunction() { cout << "Free Britney"; return; } vs. Pure virtual function: virtual void myfunction = 0; • All functions that are overridden in some subclass must be virtual in the parent • Used to achieve runtime polymorphism • Pure virtual functions are functions that must be redefined by subclasses; the base class which defines the pure virtual function is an abstract class and cannot be instantiated • Used in the template pattern (in Python, we would use the @abstractmethod decorator or raise NotImplementedError)

In the following code, what method must be defined on foo? [x for x in foo]

__iter__

Passing references in C++

int x = 3; C-style: void myfunction1(int* a) { (*a) *= 2; } // pass the address of int x myfunction1(&x); C++ style: void myfunction1(int& a) { a *= 2; } // pass x directly (do not need to get its address first) myfunction1(x);

The ______ state is shared in the flyweight object, the ______ state is not.

intrinsic, extrinsic

What methods/functions are called in the following code chunk (excluding the operators new and delete)? Person* tim = new Person("tim"); delete tim;

new: malloc Person (constructor) delete: ~Person (destructor) free

C++ Structs

• A contiguous chunk of memory • Unlike arrays, fields can have different types • Unlike classes, all fields are public • Defined using the keyword struct • Fields are accessed using the . operator Ex. struct product { int weight; double price; double calcCost(){ return weight*price;} }; struct product apple = {1, 0.95}; struct product* ptr = &apple; OR struct product apple ; apple.weight = 1; apple.price = 0.95;

Factory method

• A creational pattern • A creator class defines a factory method that returns a new product object (method can be abstract, so subclasses must implement their own method, or return a default product) • Concrete creators override the base factory method so it returns a different type (i.e. subclass) of product • The product class declares the interface shared by all products; all concrete product classes must have this same interface (via inheritance), but can have different implementations Ex. class PlayerFactory(metaclass=ABCMeta): @abstractmethod def create_player(self): return class HumanPlayerFactory(PlayerFactory): def create_player(self): return HumanPlayer()

C++ 'this' keyword

• A pointer to the current instance of the class within a method call • Similar to 'self' in Python • Not required to access instance variables/methods Ex. class Dummy { int a; public: bool isitme(Dummy& param); Dummy(int myint) : a(myint){} printint() { printf("%d", this->a); } }; Dummy::isitme(Dummy& param) { // this is a Dummy pointer if &param == this { return True; } else { return False; } }

Overloading operators in C++

• A similarity between Python and C++ • Classes can redefine operators like =, *, + • Need to define a public method called 'operator[operator]' or 'operator [operator]' Ex. operator+ or operator +, operator<< or operator << • 'operator<<' is similar to __str__ Ex. Person p; stdout << p; Ex. CVector CVector::operator+ (const CVector& param) { CVector tmp; tmp.x = x + param.x; tmp.y = y + param.y; return tmp; }

Decorator pattern

• A structural pattern • Adds capabilities to an object dynamically (without monkey patching; an alternative to the decorator) • Wraps an object with another object; wrap objects recursively • Core interface remains untouched Ex. class Component(metaclass=abc.ABCMeta): @abc.abstractmethod def operation(self): pass class Decorator(Component, metaclass=abc.ABCMeta): def __init__(self, component): self._component = component @abc.abstractmethod def operation(self): pass class ConcreteDecoratorA(Decorator): def operation(self): print("decorated by A") # calls the method of its component self._component.operation()

Facade pattern

• A structural pattern • Provides a simpler or higher-level interface to some code • A type of wrapper, like decorator and adapter • Does not provide any new functionality, like adapter Ex. for loops are a facade over iterators Ex. class VideoFile // ... class OggCompressionCodec // ... class MPEG4CompressionCodec // ... class CodecFactory // ... class BitrateReader // ... class AudioMixer // ... class VideoConverter is method convert(filename, format): File is file = new VideoFile(filename) sourceCodec = new CodecFactory.extract(file) if (format == "mp4") destinationCodec = new MPEG4CompressionCodec() else destinationCodec = new OggCompressionCodec() buffer = BitrateReader.read(filename, sourceCodec) result = BitrateReader.convert(buffer, destinationCodec) result = (new AudioMixer()).fix(result) return new File(result)

Initializer list

• A way of initializing the instance variables for a class • Particularly advantageous when a class has another object as one of its attributes; otherwise, the constructor for this object is called twice Ex. class Cylinder { Circle base; double height; public: Cylinder(double r, double h): base(r), height(h) {} };

Python multiprocessing library

• Allows one to run multiple processes at once Ex. from multiprocessing import Process, cpu_count import os class MuchCPU(Process): def run(self): print(os.getpid()) for i in range(100000): pass procs = [MuchCPU() for f in range cpu_count] for p in procs: # start the process p.start() for p in proc: # wait for this process to complete p.join()

Templates in C++

• Allows the type of a variable in a class to be determined during instantiation • Unnecessary in Python (Python is dynamically-typed) Ex. using namespace std; template <class T> class Mypair { T a, b; public: Mypair(T first, T second): a(first), b(second) {} T getmax(); }; Mypair <int> myobject(100, 75); Mypair <double> myobject(3.14, 2.72);

Composition versus Inheritance

• Composition is used as a catch-all for "has-a" relationship; is more flexible than inheritance; can swap out references to objects • Inheritance is more permanent; can never swap what its parent class is

What is refactoring?

• Comparable to editing a book prior to publication • Aims to make code "cleaner", meaning: easier to read, minimal redundancy, modular • Sometimes this means making use of design patterns • Paying off technical debt

Iterator pattern

• Behavioral pattern • Created to traverse the elements from another object • Should traverse without exposing an object's internal structure • Should not need to change the original object's interface • In languages such as C, iteration is controlled externally: Ex. for (int i = 0; i < 5; i++) { print("%d", i); } • Using the iterator pattern, iteration is controlled internally: Ex. while not (iterator.done()): print(iterator.next())

Strategy pattern

• Behavioral pattern • Implement different solutions to a problem, each in a different object • Choose the appropriate solution at runtime • Object aggregates a strategy object • Each strategy object has only one method and no data • Can be simplified using first-class functions (still strategy pattern since functions are objects) Ex. class Context: def __init__(self, strategy): self._strategy = strategy def context_interface(self): self._strategy() class Strategy(metaclass=abc.ABCMeta): @abc.abstractmethod def __call__(self): pass class ConcreteStrategyA(Strategy): def __call__(self): print("A") or could do def strategy_a(): print("A")

Observer pattern

• Behavioral pattern • Observers are subscribed to updates (subject --> observer) on one or more other objects • Observer implements an update method • An object can have multiple observers • An observer can be added or removed at runtime • Used in event-driven programming Ex. In GUIs: Binding a handler (observer) to an event queue (subject) Ex. Auctioneer is the subject, bidders are the observers; auctioneer broadcasts new high bid to the bidders • Ideally, the subject does not need to know what the observer does, it just notifies the observer to update • Subject should not "push" data to the observer why? is possible, but would need to call observer.update(data); what data to send, would need to know the implementation of observer, which is bad for abstraction; if send too much data breaks the principle of encapsulation • Instead, the observer should pull what it needs; observer would need a reference to subject; only relevant data would need to be publicly accessible Other considerations: • If many small changes are made on the subject, should update be called each time? • An observer could watch multiple subjects, but would need to know from which subject update was called; also bad for memory management (when should an observer be deleted)

Command pattern

• Behavioral pattern • Represents an action as an object • Sender (or Invoker) class holds a reference to the command object • Sender is not responsible for creating the command object • Sender defines an executecommand method that calls execute on the command object • Command object handles the details of how a request is passed to a receiver • The receiver itself does the work of performing the command (i.e. the receiver manages its own internal state) • To create a command object, one must pass all request parameters (i.e. all arguments required to perform the action), including a receiver instance • The receiver is associated with a command • Object-oriented callback • Useful for deferring execution of an action • Can help with undo, redo functionality since the action can have a method to reverse itself

Memento pattern

• Behavioral pattern • Saves the state of an object in a snapshot • Avoids exposing the details of the original class • Works well with the command pattern (command pattern calls backup on caretaker to create new memento object) • Consists of three distinct classes: the caretaker, originator, and memento • The caretaker does not access the state of the object; aggregates a history of memento objects and holds a reference to the originator; has backup and undo methods, which call save and restore on the originator • The originator class is responsible for holding the current state and producing snapshots (Momento objects) of its current state (with a save method); can also restore a previous memento object • The memento class holds the state of the originator (at some point in time); can define a getter (get_state) to return the state held by a memento object

State pattern

• Behavioral pattern • Similar to strategy pattern • Used in problems that make sense as state machines • The behavior of an object changes based on its state • Transitions may be defined in a manager class or state classes themselves

Template method pattern

• Behavioral pattern • Used to factor out duplicate code • Re-used code is defined and called in base class • Subclasses override only certain steps in a process • Template pattern is a generalization of the strategy pattern (multiple steps instead of a single method) Ex. class QueryTemplate: def connect(self): self.conn = sqlite3.connect("sales.db") ' def construct_query(self): raise NotImplementedError() def do_query(self): results = self.conn.execute(self.query) self.results = results.fetchall() def format_results(self): output = [] for row in self.results: row = [str(i) for i in row] output.append(", ".join(row)) self.formatted_results = "\n".join(output) def output_results(self): raise NotImplementedError() def process_format(self): self.connect() self.construct_query() self.do_query() self.format_results() self.output_results() class NewVehiclesQuery(QueryTemplate): def construct_query(self): self.query = "select * from Sales where new='true'" def output_results(self): print(self.formatted_results)

What are the five categories of code smells we have studied?

• Bloaters • OOP abuse • Change preventers • Dispensables • Couplers

"Super" in C++

• C++ has no super keyword • Can access the parent class' methods using the class name; this is only necessary if there is a name collision Ex. class Mother { public: int myint; Mother(int a): myint(a) {} } class Son: public Mother { // no naming conflict Son(int a ): Mother(a) {} } class Mother { public: virtual void print() {return;} } class Son: public Mother { public: void print() { cout << "foo"; // name conflict need the scope resolution operator Mother::print(); } }

Destructor in C++

• Called when an object is deleted (with delete) • Has the same name as the constructor with '~' added to the beginning • Responsible for cleaning up any dynamically-allocated instance variables Ex. class Example { string* ptr; ~Example() { delete ptr; } };

Statically-defined decorators in Python

• Can decorate either functions or methods (remember, functions are objects) • Use @decorator_name syntax before the function/method name • Less powerful: baked into code, cannot decorate an object at runtime • Often easier to read Ex. @abstractmethod def mymethod(self): ... @classmethod def myclassmethod(cls): ...

Process pool pattern

• Concurrency pattern • It is not beneficial to have more processes than cores; processes sit idle • Create as many processes as cores (reused for many tasks); put these processes into a pool that is managed by some code • Do not manage interprocess communication • Pass tasks to process pool, will return to pool of tasks until all are complete The map method on the Pool class applies a function to each element in some iterable, collects results into a list • Map organizes processes that it has set up, passes job to processes, knows when jobs have completed • Nothing else happens until job is completed Ex. pool = Pool() pool.map(prime_factor, to_factor) The map_async method • Can continue running other things while wait for job to finish • Returns a map object • wait for the results, then get them Ex. results = pool.map_async(prime_factor, to_factor) print("waiting for prime factorizations") # can even add more jobs to pool results2 = pool.map_async(prime_factor, [543421]) results.wait() results = results.get() results2.wait() results2.get() • pool.close() waits for all jobs to finish

Queue pattern

• Concurrency pattern • Need to allocate jobs to processes (unlike with pools, where this is done automatically) • Create a queue corresponding to each process • put jobs into the queue corresponding to each process; when nothing in queue, the process waits • In code example, each process terminates when None is passed to the process queue • multiple processes can share a results queue; when one process is writing to the queue, the other processes need to wait their turn; do not need to worry about synchronization • Need to get from the results queue Ex. for match in results_queue.get():

When should one use the adapter pattern?

• Converting arguments to a different format • Rearranging the order of arguments • Calling a differently named method • The adapter pattern does not provide new behavior to an object, unlike the decorator pattern

Decorator UML

• Core and decorator objects implement the same interface • Decorator objects hold a reference to another interface object (either the core or another decorator) • Can also have an ABC which defines the interface of concrete decorator classes

Singleton pattern

• Creational pattern • Make sure a class only ever has one instance • Lazy initialization: delaying the creation of an object, the calculation of value, or some other expensive process until the first time it is needed • Global access: instance is accessed through the class name • Use the Python constructor __new__ to ensure only one instance is ever created Ex. class OneOnly: _singleton = None def __new__(cls, *args, **kwargs): if not cls._singleton: # Notice that we pass the class-not an object instance-to super cls._singleton = super(OneOnly, cls ).__new__(cls, *args, **kwargs) return cls._singleton

Iterator UML

• Each ConcreteIterator inherits from the Iterator class, which defines the interface for Iterator objects • Each iterator typically defines the has_more and next methods • Each iterable object has a createIterator method that returns an iterator for that object

What is a process?

• Everything needed to run a program • Created by the operating system Consists of... • process id • virtual address space (memory that process can use) • code • handles to open file (and other resources) • security context (what user is running this, what permissions does the user have)? • environment variables • at least one main thread

What is the dining philosophers problem?

• Frive philosophers sitting at a round table • There is a fork between each two plates • Eating requires two forks • An obvious solution: start with one philosopher, move around the table • Deadlock: each philosopher picks up the fork on the left

C++ Classes

• Functionally nearly identical to structs, but default visibility is private • Need to explicitly specify which methods, attributes are public, protected • Defined using the keyword class • Methods can be defined outside the class definition • Do not need to reference the object instance with 'self' • The :: operator is used when defining a method outside of a class and to access a class' static variables • Otherwise, attributes and methods are accessed using the . operator Ex. class Rectangle{ int width, height; public: void set_values(int, int); int area(){return width*height;} } ; void Rectangle::set_values(int x, int y) { width = x; height = y; }

What are design patterns?

• General solutions to commonly-occurring problems • Not finished code, but rather a template

What is the Python GIL?

• Global Interpreter Lock • Python implementation (C Python) not Python language • Only one thread can execute Python bytecode at a time Why does the GIL exist? • Prevents race conditions (behavior of program depends on the timing on relative timing or interleaving of multiple threads or processes) and ensures thread safety • Necessary for Cpython's memory management

How are iterators built into Python, C++?

• In Python, all for-loops use the iterator pattern: Ex. for i in range(n): print(i) •In C++, incrementing pointers steps through arrays (considers the size of objects) Ex. ptr++ *ptr

Polymorphism in C++

• In order to achieve runtime polymorphism, one must implement a virtual function in the parent class • That is, when accessing an object as an instance of its parent class, only have access to the interface of parent Ex. class Polygon { protected: int width, height; public: Polygon(int w, int h): width(w), height(h) {} virtual int area() {return 0;} }; class Triangle: public Polygon { public: int area() { return (width * height / 2); } }; class Rectangle: public Polygon { public: int area() { return width * height; } }; // if we do not include the virtual function, // then we cannot do Triangle mytriangle(4, 6); Rectangle myrectangle(4, 6); Polygon mypolygons[2]; mypolygons[0] = mytriangle; mypolygons[1] = myrectangle; for (i=0; i < 2; i++) { cout << mypolygons[i].area(); }

Static variables in C++

• Initialized only once • Shared by all instances of a class • There is not a distinction between class and static variables in C++, as there is in Python • Static variables cannot be initialized using constructors • Defined using the static keyword Ex. Class Dummy { public: static int n; Dummy() { n++; } }; int Dummy::n = 0;

What are the invoker, command, and receiver in the following diagram?

• Invoker: button/menuitem/shortcut • Command: SaveCommand • Receiver: computer hard drive

Iterators in Python

• Iterable class must implement the __iter__ method • __iter__ returns an iterator object • The iterator must implement the __next__ method; __next__ must raise a StopIteration exception when it is done iterating Ex. class CapitalIterable: def __init__(self, string): self.string = string def __iter___(self): return CaptialIterator(self.string) class CapitalIterator: def __init__(self, string): self.words = [w.capitalize() for i in string.split()] self.index = 0 # __next__ takes a single argument def __next__(self): if self.index == len(self.words): raise StopIteration() word = self.words[self.index] seld.index += 1 return word a = CapitalIterable("hello world") # initializes an iterator, calls __next__, and handles the StopIteration exception automatically for x in a: print(x) # can manually access an iterator object iterator = inter(a) while True: try: print(next(iterator)) except StopIteration: break # notice __iter__ and __next__ are magic methods

References in C++

• Like a const pointer • Unlike a pointer, does not need to be dereferenced to use that value Ex. int p = 5; pointer: int* myint = &p; (*myint)++; reference: int& myint = p; myint++;

Abstract factory pattern

• Like the factory pattern, but there are multiple factory methods defined on a single object • Various abstract product classes, each of which defines an interface that subclasses must implement Ex. class chair: @property @abstractmethod def wood(self): return @property @abstractmethod def style(self): return • The abstract factory interface (an ABC) defines the factory methods for creating each of the abstract products • Each concrete factory must override these factory methods to return the particular subclasses of products

What are some use cases for the singleton pattern?

• Logging objects (access a single [global] instance) • Application configuration • Objects with no internal state (as in the strategy or state patterns) • Objects with read-only state

Adapter UML (composition)

• Note: the adapter composes the adaptee (appears the other way around in the UML class diagram)

Inheritance in C++

• Only public and protected attributes, methods are inherited from the parent class • Indicate that a class inherits from a parent class with the : operator • Public, protected, and private inheritance • In public inheritance, public attributes/methods are inherited as public, protected attributes/methods are inherited as protected, private attributes/methods are not inherited • In protected inheritance, public and protected attributes/methods are inherited as protected, ... Ex. class Polygon { protected: int width, height; public: Polygon(int w, int h): width(w), height(h){}; }; class Rectangle: public Polygon { public: int area() { return width*height; } };

When should one refactor?

• Rule of three (when write similar code three times) • When adding a feature • When fixing a bug • During a code review

What is a thread?

• Scheduled for execution on a core of the CPU (a core is a CPU's processor; each core can focus on one task (thread) at a time; the more cores a CPU has, the more efficient it is) • Part of a process • Has a shared virtual address space (with other threads in the same process) i.e. all threads can access the process' memory, may have synchronization issues • Execution context (metadata): program counter (where thread is executing in the code), machine registers (each core has its own registers), stack (memory space partitioned into stacks, each thread has its own stack)

What are code smells

• Signs of problematic code • Incur technical debt (refactoring pays off technical debt) • Primary targets when refactoring • A balancing act: one code smell could lead to another

Why learn design patterns?

• Speed up development • Less likely you will need to refactor your code • Makes code more readable to others who know the pattern • Build up vocabulary to communicate with other developers/managers

What is the difference between the state and strategy patterns?

• Strategy pattern is used to choose an algorithm at runtime (typically only one algorithm will be chosen for a particular use case), whereas state pattern allows for switching between different states dynamically • In code, strategy objects are not aware of one another; state objects need to know which other states they can switch to

Composite pattern

• Structural pattern • Building trees through object references • Polymorphism allows individual objects (leaves) and collection objects (nodes) to be treated as one type (more important for statically-typed languages ex. C++) • Identical UML diagram to the decorator pattern • The component interface is an ABC that defines operations common to both the leaf and composite objects; includes an execute method • The leaf class is a basic element of a tree with no subelements, the composite class aggregates other components (either composite or leaf instances) • The composite class typically also defines add, remove, and get_children methods • The composite class does not know the subclasses of its children • The composite delegates work to its sub-elements (with execute), processes intermediate results, and then returns the final result to the client

Adapter pattern

• Structural pattern • Converts an interface into another interface • Allows existing objects to work together without modifying their rigid public interfaces • A wrapper pattern, like the decorator, but the decorator does not change the object's interface (enhances an object without changing its interface) • Does change the adapter object's interface • Can be implemented using either multiple inheritance or composition Ex. (with multiple inheritance) class Target: def request(self) -> str: return "Target: The default target's behavior." class Adaptee: def specific_request(self) -> str: return ".eetpadA eht fo roivaheb laicepS" class Adapter(Target, Adaptee): # NOTICE: the adapter implements the same interface as its target def request(self) -> str: return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}" • In C++ we inherit publicly from the target, but privately from the adaptee Ex. class RectangleAdapter: public Rectangle, private LegacyRectangle **see LegacyRectangle example in C++

Flyweight pattern

• Structural pattern • When creating hundreds or thousands of separate objects, we are using a lot of memory for identical data • The flyweight pattern saves memory by keeping the shared state in a single object • The intrinsic state is independent of the context, is shared in the flyweight object • The behavior of the original object usually remains in the flyweight class; if in the context class, the flyweight just serves as a data object • The extrinsic state is specific to the context; is passed to the flyweight object when calling methods • The flyweight factory manages a pool of existing flyweights; the client passes intrinsic data to the flyweight factory, which either returns an existing flyweight or creates a new flyweight • The flyweight pattern is meant for memory optimization • Good in certain scenarios, but overkill for others (only necessary if creating many object instances) • Tradeoff: less memory, more complexity

What are the challenges in concurrent programming?

• Synchronizing access to memory (threads writing to same memory) • Where and how to split up the work? (if have 60,000 images to process, don't need 60,000 threads) • Waiting for resources or conditions: reduces the advantages of parallelism (keep waiting on threads); deadlock [dining philosopher's problem] i.e. all threads are waiting for access to resources) • Nondeterminism: unforeseen bug; problem with scheduling • Overhead: context switching (switching from one thread to another), communicating between processes

Constant variables

• The const keyword specifies that a variable's value is constant • References the type on the left, except when const is the leftmost expression, in which case it references the type on the right Ex. const int c = 5; is the same as int const c = 5; • Pointer to a constant value: const int* p; • Constant pointer: int* const p = &x; • Constant reference: const int& param; (In the above example, we cannot do something like 'param = 5;')

Why in the factory and abstract factory patterns must all products implement the same abstract interface?

• This way, the client code does not depend on the specific variant of product returned from a factory (i.e. code is not coupled with the product) Ex. not if isinstance(product, Apple): product.munch() if isinstance(product, Popsicle): product.lick() instead # all food products have a common interface product.eat() • This way, client can work with any concrete factory and product

Constructor/Initializer in C++

• Unlike Python, C++ does not have a separate constructor and initializer • The C++ initializer has name matching the class name • The constructor does not have a return type • Can overload the constructor with different parameters • An alternative to *args, **kwargs in Python • Can initialize instance variables in the constructor body or the initializer list Ex. class Construct { public: float area; // Constructor with no parameters Construct() { area = 0; } // Constructor with two parameters Construct(int a, int b) { area = a * b; } }; int main() { // Calls the first constructor Construct obj1(); // Calls the second constructor Construct obj1(4, 5); }

In Python, when should we use processes versus threads?

• Use threads if the task is I/O (input-output) heavy Ex. thread is waiting for input on the command line (has nothing to do, not taking up time on the CPU); main thread can execute while other thread is waiting Ex. waiting on network requests; first ping the request from each thread, wait for results to come back in Does not violate the GIL: only one thread is ever running at a time • Use processes if the task is CPU heavy (calculation; spend a lot of time on the core assigned) • Use neither if performance or maintenance overhead outweighs the benefits

Copy constructors C++

• Used automatically when assigning an object to another of the same type • Takes the form ClassName(const ClassName& old_obj); • Uses an implicit copy constructor if not defined; however, this constructor may not make a deep copy (unreliable) Ex. class Example { string* ptr; public: Example (const Example& x) : ptr(new string(x.content())) {} }

Generators

• Used if one would like to process a sequence without pulling a new list, set, or dictionary into memory i.e. don't need a complete container of objects over which we will iterate (ex. a 2 TB log file) • Can be created by wrapping a list comprehension in parentheses Ex. # a generator, NOT a tuple # notice: infile is a list warnings = (l for l in infile if 'WARNING' in l) for l in warnings: outfile.write(l) • The key to generator objects is the yield keyword • yield is similar to a return statement in the sense that it exits the function and returns a line; • Unlike return, though, when the function is called again via next(), it will start where it left off (the statement immediately after yield) Ex. def collatz(n): while n != 1: if not n % 2: n = n // 2 else: n = 3*n + 1 yield n • What is actually going on with generators? Python wraps the function in an iterable object which defines both __iter__ and __next__; whenever next() is called, the generator runs the function until it finds a yield statement

yield from keyword

• Used to yield data from an iterable object (ex. another generator, a list) Ex. yield from ( l.replace('\tWARNING', '') for l in infile if 'WARNING' in l )

Facade UML (example)

• Uses aggregation and/or composition in the facade wrapper class

List comprehensions

• Uses the iterator pattern • Much faster than standard for-loops when iterating over a large number of items; however, often not as readable • Any object that implements __iter__ can be the input to a list comprehension • Has the basic format [{method or function}i for i in myobjext if {conditional}] Ex. [i.capitalize() for i in "hello word" if i > 'h'] >> ['L', 'L', 'O', 'W', 'O', 'R']

Why is the singleton pattern problematic?

• Very situational • Why should x be made global in the first place? • Troublesome for concurrent code • Maybe the code should allow for multiple instances some day • Could pass around an object in method parameters rather than making it global

An alternative to the decorator pattern is ______.

• [Multiple] inheritance • Monkey patching (create an object's interface at runtime) • If there are many different decorators, multiple inheritance becomes infeasible; need to call parent methods with super (unpredictable in which order the parent methods will be called) • Decorators can be dynamically added to objects at runtime, multiple inheritance is permanent

Async/await coroutines

• await keyword allows other code to run until it gives up its priority • Threading • Uses the asyncio module • Like pool, give jobs to complete • Only aync functions can call await, only aysnc functions can be awaited • await asyncio.sleep() suspends the current task, allowing other coroutines to run Ex. import asyncio import random # await is allowed only within async functions async def random_sleep(counter): delay = random.random() * 5 print("{} sleeps for {:.2f} seconds".format(counter, delay)) await asyncio.sleep(delay) print("{} awakens".format(counter)) async def five_sleepers(): print("Creating five tasks") tasks = [asyncio.create_task(random_sleep(i)) for i in range(5)] print("Sleeping after starting five tasks") # this line allows other coroutines to execute await asyncio.sleep(2) print("Waking and waiting for five tasks") await asyncio.gather(*tasks)

Constant methods and objects

• const methods cannot be used to alter an object's attributes • This is because the 'this' pointer passed to a const method is a pointer to a const object Ex. // const keyword comes after the method int get_month() const; • Constant object instances can only be modified by their constructor and destructor Ex. const Loan myloan(100); // cannot do myloan.lower_amount(10) • Const methods can always be called (on both const and non-const objects) • Const methods cannot call a non-const method • Non-const methods cannot be called on a const object


Conjuntos de estudio relacionados

Anatomy and Physiology Unit 1 Quiz (Intro to AP)

View Set

2.21, 2.22 Bone and Joints 1 and 2

View Set

Advantages of Sole Proprietorships for New Businesses

View Set

integrated science b - unit 1: scientific thinking and motion lessons 1-4

View Set

Chapter 5 - The English Monarchy

View Set

PN NCLEX 6th Edition-Pharmacology Renal/Urinary

View Set