Skip to content

Problem List

  1. Class 8: The implementation of an ADT might not be different than the implementation of another. A LinkedList can be used to implement Lists, Sets, Collections (*), Queues, Stacks, Deques, etc. Is this a good approach? What about class invariants?

    Yes—a linked-list can power many ADTs (lists, sets, collections, queues, stacks, deques, etc.).
    But class invariants complicate things: some ADTs (e.g., a set) must inspect the whole list to ensure no duplicates, whereas queues, stacks, and deques need no extra checks.

    Reusing the list saves effort by simply exposing the right interfaces, yet it also crams every method from all those ADTs into one class, mixing unrelated responsibilities and lowering cohesion. So reuse brings both clear benefits and clear drawbacks.

  2. Comparable, and Comparable<? super T>

    Comparable: must compare to its own type T only.
    Comparable<? super T>: may compare to T or any of T’s supertypes—more flexible.

  3. Comparator

    Comparable: object defines its own natural order via compareTo ( this vs. other ).
    Comparator: separate object that defines arbitrary orderings via compare(a, b), letting you sort the same type in multiple different ways(customize).

  4. List<Long> l = new LinkedList<Long>(); or LinkedList<Long> l = new LinkedList<Long>();

    List l = new LinkedList();
    • Variable typed to the interface List.
    • You can later swap in any other List implementation (e.g., ArrayList) without changing the rest of the code.
    • Only List-level methods are available at compile time.

    LinkedList l = new LinkedList();
    • Variable typed to the concrete class.
    • Tied to LinkedList; harder to replace with another List type.
    • Gives access to LinkedList-specific methods (like addFirst, removeLast) in addition to the List interface.

  5. What the use of .parallel() in stream?

    .parallel() turns the stream into a parallel stream: the elements are processed by multiple thread

  6. Class 9

    Implementing a sort method

    Let’s use selection sort to keep it simple

    What if we want a different ordering of our elements (like, sort in reverse order), what can we do?

    Change comparator to negative

  7. Task 6 Can you have proper generic classes and methods in Python, justify?

    Yes, Python supports proper generic classes and Yes—Python supports generics (TypeVar) for static type-checking. The type parameters are only metadata; the interpreter doesn’t enforce them at runtime

  8. Explain

    image

    Memory is a sequence of bytes. Every address has a value.

  9. struct

    Behaves like class except all fields are public.

  10. const everywhere

    const T * data;
    
    Cannot change the value pointed to var.

    Value is a constant but the pointer is not

    T * const data;
    
    Cannot change the pointer address.

    Pointer is constant but the value is not.

    const T * const data;
    
    Fix everything.


    const after function name: function body does not change any state.

  11. NULL and nullptr in C++

    NULL is a macro expands to 0 (or ((void *)0)).
    nullptr is a type that unambiguously represents “no pointer” in C++.

  12. Why you should NOT return pointers to a function's local variables.

    • Local variables will be destoryed when leaving the function
    • Memory previously occupied by local variables is now considered "garbage" or available for reuse.
    • There is no guarantee that the value will still be the one that you want.
    #include <stdlib.h>
    #include <stdio.h>
    
    int * foo(int baseValue) {
        int myLocalVariable = baseValue;
        if (myLocalVariable % 2 != 0) {
            myLocalVariable++;
        } else {
            myLocalVariable = myLocalVariable * 2;
        }
        return &myLocalVariable; // DANGER: Returning address of local variable
    }
    
    int bar(int baseValue) {
        int myLocalVariable = baseValue;
        if (myLocalVariable % 2 != 0) {
            myLocalVariable--;
        } else {
            myLocalVariable = myLocalVariable / 2;
        }
        return myLocalVariable; // SAFE: Returning value
    }
    
    int main(void) {
        int * ptrToValue = foo(32); // ptrToValue gets address of foo's myLocalVariable (which was 64)
                                    // foo's stack frame is now GONE. ptrToValue is dangling.
        printf("Printing foo's local variable: %d\n", *ptrToValue); // UNDEFINED BEHAVIOR
        printf("Printing bar's return value: %d\n", bar(32));      // bar(32) returns 16. Safe.
                                                                    // The call to bar and printf likely overwrote
                                                                    // the memory ptrToValue points to.
        printf("Re-printing foo's local variable: %d\n", *ptrToValue); // UNDEFINED BEHAVIOR, very likely garbage or crash
    }
    
  13. Two ways to use a method of a.cpp in main.cpp

    1. a.hpp

      #ifndef A_H          
      #define A_H       
      
      void foo();
      
      #endif    
      
      a.cpp

      #include "a.h"
      void foo() {
         //.....
      }
      
      main.cpp

      #include "a.h"  
      int main() {
          foo();
          return 0;
      }
      
      2. ​a.cpp

      void foo() {
         //.....
      }
      
      main.cpp

      extern void foo();  
      int main() {
          foo();
          return 0;
      }
      
  14. Templates in C++

    Compiler will specialize different functions for different type usages.

    Advantages: code generated during compilation.

    Disadvantage: duck-typing(A template accepts any type. During instantiation the compiler simply checks “does the type support every operation I happen to use inside the template?” If the answer is yes, the code compiles; if not, the instantiation fails.)

    Specifying restrictions using concepts (template types itself does not add any constraints).

    typedef Stack<float> FloatStack;
    
    FloatStack fs = FloatStack(5);
    
    Since C++20.

    Adds constraints to templates.

    concept Comparable = requires(T a, T b) {
       { a.compares_to(b) } -> std::same_as<int>;
    }
    
    which requires T to have a member function int compare_to(T other).

  15. Destructor

    Value data members are destructed automatically when the parent object gets destructed.

    ## Static vs non-static Java

    Static does not require an instance or a object, while non-static does.

  16. Singleton

    • Design pattern that guarantees exactly one instance of a class and provides global access to that instance.

    ### Nested class

    • A class declared inside another class (“enclosing class”).
    • Purpose: grouping—indicates the inner class is used only by its outer class, can access its private members if declared friend or is private itself.
    • Visibility modifiers (public, protected, private) on the nested definition control how clients see it; it does not automatically get access to outer members unless such access is granted.

  17. image

    #### 1. Why an array of pointers to Figure?

    Because we need to store different child types (like Circle and Rectangle) in one list. This lets C++ use polymorphism—calling the right draw() for each shape.

    #### 2. We cannot define a variable of class Figure, why?

    Figure is an abstract class because it has a pure virtual function (like virtual void draw() = 0;). This means Figure can not be instantied

  18. image

    #### 1. Can we have multiple implementations of these types and functions at the same time?

    • Simple answer: Yes! This is the point of data abstraction. You can have different "versions" (implementations) of the list—like one using arrays (fast for random access) and another using linked nodes (good for inserting/deleting). Each version defines the same functions (e.g., add, size) but works differently inside. In C++, you could use classes or templates to switch between them without changing your main code. It's like having two car engines that fit the same car—you pick one based on what you need (speed vs. fuel efficiency).

    #### 2. Can we use multiple implementations of these types and functions at the same time?

    • Simple answer: Absolutely, and it's useful! In the same program, you could create one list using an array implementation (e.g., ArrayList myList1;) and another using a linked list (e.g., LinkedList myList2;). Both would have the same functions (like size() or add()), so your code treats them the same way.

    #### 3. Why choose the name list.size?

    • Simple answer: We choose size because it's clear and describes exactly what it does—returns how many items are in the list (e.g., 0 for empty, 5 for a list with 5 things). It's like naming a button "Play" on a music app instead of "DoThing42"—easy to understand and remember. In C++, this could be a member function like int List::size() const { return itemCount; }. The slide mentions for a NULL (empty) list, size returns 0, which makes sense—no items means size zero!

    #### 4. Why choose the name list.drop?

    • Simple answer: drop is a simple name that means "get rid of" or "delete" the list and free up its memory. It's like dropping trash in a bin—you're cleaning up. In C++, this could be like a destructor (~List()) or a function to clear everything (e.g., void List::drop() { /* free memory */ }). We pick short, meaningful names so code is easy to read, not confusing like "destroyListNow".

    #### 5. Can we have a "List of T" where T is a specific type?

    • Simple answer: Yes, definitely! This is where C++ shines with templates. You can make a generic List<T> where T is a placeholder for any type—like List<int> for a list of numbers, or List<string> for a list of words. It's like a reusable box that can hold apples (int) or oranges (string)—you specify the type when you create it. In code: template <typename T> class List { /* functions like add(T item) */ };. The slide's example seems like a basic int list, but templates make it flexible for any "T".
  19. image

    Data abstraction is one of the most essential and important features of object-oriented programming in C++. Abstraction means displaying only essential information and ignoring the details. Data abstraction refers to providing only essential information about the data to the outside world, ignoring unnecessary details or implementation.

    Data abstraction - This type only shows the required information about the data and ignores unnecessary details.

  20. Every expression has a type. For type checking, etc.(The compiler knows the type of every expression before the program runs.)

  21. Python does not have genericity because No strict mechanism for constraining types.

  22. Difference between function and method

    ### Function

    Object independent. Can only have side effects on global variabls.

    int add(int a, int b)            // pure function example
    {
        return a + b;                // no hidden state touched
    }
    
    ### Method

    Object dependent. Can affect object internals.

    class Counter {
        int value_{0};               // object’s private data
    public:
        void increment() { ++value_; }    // method mutates *this*
        int  value()   const { return value_; }
    };
    
  23. Modularization

    Java: class. C++: header. Python: module

  24. Java

    OOP

    Genericity can only be used with classes(object types).

    Generic arrays can only be created from specific types, no generic array creation is allowed.

    class Box<T> {
        // T[] a = new T[10];  error
    }
    
    Functions cannot be passed as arguments directly in Java, they are objects underneath.

    Universal bytecode, specific JVM.

    JIT compiler is provided (bytecode to native code on runtime if they are being run frequently).

    Static type checking (compilation time)

    Runtime type checking when for example casting and instanceof

    Interpreted (compile first)

    ## Python

    Everything is an object (local variable, function, class, field, method, etc.)

    Flexible.

    Dynamic type checking during runtime.

    No way to define type restrictions.

    Interpreting, without preprocessing.

    Duck typing.

    Define before use.

    ## C++

    Multiparadigm.

    Support procedual, object-oriented, functional, etc.

    Overload override (function/operator)

    Naming collision issue (same name between variables and functions)

    Static type checkng

    Generics are supported by templates, but copying class/structure/etc.

    Templates do not offer restrictions.

    Solutions:

    Leave it to compilers

    Parameterized abstraction (require generic function for every operation)

    Concepts