Skip to content

Practical example

Argument, package, precondition, postcondition, invariants, exception

image

Main.java

import Person.Person;

public class Main {

    public static void main(String[] args) {
        //print the arguments
        for (String arg : args) {
            System.out.print(arg);
        }
        System.out.print(args.length);

        //create 4 persons
        Person PersonA = new Person("John", "Wick", 60, 420000047);
        Person PersonB = new Person("Wick", "John", 60, 420000047);
        Person PersonC = new Person("Wohn", "Jick", 60, 420000048);
        Person PersonAClone = new Person("John", "Wick", 60, 420000047);
        System.out.println(PersonA.toString());
        System.out.println(PersonB.toString());
        System.out.println(PersonC.toString());
        System.out.println(
                PersonA.toString() + " == " + PersonAClone.toString() + "? " +
                (PersonA == PersonAClone));
        System.out.println(
                PersonA.toString() + ".equals(" + PersonAClone.toString() + ")? " +
                PersonA.equals(PersonAClone));
    }
}
---
output
0
Person {name=John, surname=Wick, age=60, id=420000047}
Person {name=Wick, surname=John, age=60, id=420000047}
Person {name=Wohn, surname=Jick, age=60, id=420000048}
Person {name=John, surname=Wick, age=60, id=420000047} 
== Person {name=John, surname=Wick, age=60, id=420000047}? false
Person {name=John, surname=Wick, age=60, id=420000047}.equals
(Person {name=John, surname=Wick, age=60, id=420000047})? true

Person/Person.java

package Person;

/**
* This class represents a Person with name, surname, age, and id.
* Invariant:
* <ul>
* <li>name and surname cannot be null.</li>
* <li>name and surname cannot be empty.</li>
* <li>name and surname can only contain letters.</li>
* <li>name and surname must be capitalized.</li>
* <li>age must be greater than zero (0).</li>
* <li>id cannot start with a zero (0), and must have exactly 9 digits.</li>
* </ul>
*/
public class Person {

    private static final int HUNDRED_MILLON = 100000000;

    private String name;
    private String surname;
    private int age;
    private int id;

    /**
    * Constructs a new Person.
    * @param name the name of the Person
    * @param surname the surname of the Person.
    * @param age the age of the Person.
    * @param id the id of the Person.
    * preconditions:
    * <ul>
    * <li>name and surname cannot be null.</li>
    * <li>name and surname cannot be empty.</li>
    * <li>name and surname can only contain letters.</li>
    * <li>name and surname must be capitalized.</li>
    * <li>age must be greater than zero (0).</li>
    * <li>id cannot start with a zero (0), and must have exactly 9 digits.</li>
    * </ul>
    */
    public Person(String name, String surname, int age, int id) {
        if (!validateString(name)) {
            throw new IllegalArgumentException("invalid name.");
        }
        if (!validateString(surname)) {
            throw new IllegalArgumentException("invalid surname.");
        }
        if (age < 1) {
            throw new IllegalArgumentException("age not positive (greater than zero).");
        }
        if ((id - HUNDRED_MILLON) < 0) {
            throw new IllegalArgumentException("id has less than 9 digits.");
        }
        this.name = name;
        this.surname = surname;
        this.age = age;
        this.id = id;
        if (!repOk()) {
            throw new IllegalStateException("Invariant violated");
        }
    }

    /**
    * @return the name of the Person
    */
    public String getName() {
        if (!repOk()) {
            throw new IllegalStateException("Invariant violated");
        }
        return name;
    }

    /**
    * @return the surname of the Person
    */
    public String getSurname() {
        if (!repOk()) {
            throw new IllegalStateException("Invariant violated");
        }
        return surname;
    }

    /**
    * @return the age of the Person
    */
    public int getAge() {
        if (!repOk()) {
            throw new IllegalStateException("Invariant violated");
        }
        return age;
    }

    /**
    * @return the id of the Person
    */
    public int getId() {
        if (!repOk()) {
            throw new IllegalStateException("Invariant violated");
        }
        return id;
    }

    //TODO: complete with setter methods, i.e.: methods to set new values for each field.

    /**
    * @return a representation of this Person
    */
    @Override
    public String toString() {
        return "Person {name=" + name +
                        ", surname=" + surname +
                        ", age=" + age +
                        ", id=" + id + "}";
    }

    /**
    * @param other the object to compare with
    * @return {@code true} iff this Person is equal to other.
    */
    @Override
    public boolean equals(Object other) {
        if (other == null) {
            return false;
        }
        if (!(other instanceof Person)) {
            return false;
        }
        Person otherAsPerson = (Person) other;
        if (!name.equals(otherAsPerson.name)) {
            return false;
        }
        if (!surname.equals(otherAsPerson.surname)) {
            return false;
        }
        if (age != otherAsPerson.age) {
            return false;
        }
        return id == otherAsPerson.id;
    }

    /**
    * @return {@code true} iff the invariant is satisfied.
    */
    public boolean repOk() {
        if (!validateString(name)) {
            return false;
        }
        if (!validateString(surname)) {
            return false;
        }
        if (age < 1) {
            return false;
        }
        return (id - HUNDRED_MILLON) >= 0;
    }

    private boolean validateString(String string) {
        if (string == null) {
            return false;
        }
        if (string.trim().isEmpty()) {
            return false;
        }
        if (string.length() != string.trim().length()) {
            return false;
        }
        if (!string.substring(0, 1).toUpperCase().equals(string.substring(0, 1))) {
//substring(int beginIndex, int endIndex)
            return false;
        }
        return true;
    }   
}

Junit test for above program

package Person;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class PersonTest {
    @Test
    void testValidPersonCreationAndGetters() {
        System.out.println("Running testValidPersonCreationAndGetters...");
        // Arrange (specific inputs for this test)
        String expectedName = "Alice";
        String expectedSurname = "Smith";
        int expectedAge = 25;
        int expectedId = 987654321;
        // Act
        Person newPerson = new Person(expectedName, expectedSurname, expectedAge, expectedId);
        // Assert
        assertNotNull(newPerson, "Person object should not be null after valid construction.");
        // Verify toString() output
        String expectedToString = "Person {name=Alice, surname=Smith, age=25, id=987654321}";
        assertEquals(expectedToString, newPerson.toString(), "toString() should return the expected formatted string.");
        // Verify that the invariant holds for the valid object
        assertTrue(newPerson.repOk(), "repOk() should be true for a valid Person object.");
    }

    @Test
    void testConstructor_NullName_Negative() {
        System.out.println("Running testConstructor_NullName_Negative...");
        // Act & Assert
        IllegalArgumentException thrown = assertThrows(
                IllegalArgumentException.class,
                () -> new Person(null, "Doe", 30, 123456789),
                "Expected IllegalArgumentException for null name."
        );
        assertEquals("invalid name.", thrown.getMessage(), "Exception message mismatch for null name.");
        System.out.println("testConstructor_NullName_Negative finished successfully.");
    }

Inheritance, interface.... Generic

Java one example

List.java

package Task1_2;

public interface List<E> {
    //appends a value to the list
    void append(E value);

    //returns the element at a valid index
    E at(int index);

    //removes an element at a valid index
    void remove(int index);

    //filters all elements that satisfies the predicate
    List<E> filter(Function<E, Boolean> predicate);

    //maps a function to all elements and return a list with the results
    <T> List<T> map(Function<E, T> mappingFunction);

    //educes all elements in a list to one value by using a binary function
    E reduce(Function<E, Function<E, E>> binaryFunction, E neutralValue);

    //return the first index of an element that satisfies the predicate
    Optional<Integer> indexOf(Function<E, Boolean> predicate);

}

AbstractList.java

package Task1_2;

public abstract class AbstractList<E> implements List<E> {

    //appends a value to the list
    public abstract void append(E value);

    //returns the element at a valid index
    public abstract E at(int index);

    //removes an element at a valid index
    public abstract void remove(int index);

    //returns the number of elements in the list
    protected abstract int size();

    //returns a new empty list instance parameterized by U
    protected abstract <U> List<U> newList();

    //filters all elements that satisfies the predicate
    public List<E> filter(Function<E, Boolean> predicate) {
        List<E> result = newList();
        for (int i = 0; i < size(); i++) {
            E element = at(i);
            if (predicate.apply(element)) {
                result.append(element);
            }
        }
        return result;
    }

    //maps a function to all elements and return a list with the results
    public <T> List<T> map(Function<E, T> mappingFunction) {
        List<T> result = newList();
        for (int i = 0; i < size(); i++) {
            result.append(mappingFunction.apply(at(i)));
        }
        return result;
    }

    //educes all elements in a list to one value by using a binary function
    public E reduce(Function<E, Function<E, E>> binaryFunction, E neutralValue) {
        E result = neutralValue;
        for (int i = 0; i < size(); i++) {
            E element = at(i);
            result = binaryFunction.apply(result).apply(element);
        }
        return result;
    }

    //return the first index of an element that satisfies the predicate
    public Optional<Integer> indexOf(Function<E, Boolean> predicate) {
        for (int i = 0; i < size(); i++) {
            if (predicate.apply(at(i))) {
                return Optional.of(i);
            }
        }
        return Optional.empty();
    }

}

LinkedList.java

package Task1_2;

public class LinkedList<E> extends AbstractList<E> {
    // Node class for singly linked list
    private static class Node<E> {
        E data;
        Node<E> next;
        Node(E data) {
            this.data = data;
            this.next = null;
        }
    }

    private Node<E> head;
    private Node<E> tail;
    private int size = 0;

    public LinkedList() {
        head = null;
        tail = null;
        size = 0;
    }

    @Override
    public void append(E value) {
        Node<E> newNode = new Node<>(value);
        if (head == null) {
            head = newNode;
            tail = newNode;
        } else {
            tail.next = newNode;
            tail = newNode;
        }
        size++;
    }

    @Override
    public E at(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index out of bounds: " + index);
        }
        Node<E> current = head;
        for (int i = 0; i < index; i++) {
            current = current.next;
        }
        return current.data;
    }

    @Override
    public void remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index out of bounds: " + index);
        }
        if (index == 0) {
            head = head.next;
            if (head == null) {
                tail = null;
            }
        } else {
            Node<E> prev = head;
            for (int i = 0; i < index - 1; i++) {
                prev = prev.next;
            }
            Node<E> removed = prev.next;
            prev.next = removed.next;
            if (removed == tail) {
                tail = prev;
            }
        }
        size--;
    }

    @Override
    protected int size() {
        return size;
    }

    @Override
    protected <U> List<U> newList() {
        return new LinkedList<>();
    }
}

Optional.java

package Task1_2;
public class Optional<E> {
    private final E value;

    private Optional(E value) {
        this.value = value;
    }

    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    public static <T> Optional<T> empty() {
        return new Optional<>(null);
    }

    public boolean isPresent() {
        return value != null;
    }

    public E get() {
        if (value == null) {
            throw new java.util.NoSuchElementException();
        }
        return value;
    }
}

Function.java

package Task1_2;
@FunctionalInterface
public interface Function<A, B> {
    B apply(A a);
}

Main.java

package Task1_2;

public class Main {
    public static void main(String[] args) {
        // Create a LinkedList of Integers
        LinkedList<Integer> list = new LinkedList<>();
        System.out.println("Appending values 1 to 5");
        for (int i = 1; i <= 5; i++) {
            list.append(i);
        }

        // Print size and elements
        System.out.println("List size: " + list.size());
        System.out.print("List elements: ");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.at(i) + " ");
        }
        System.out.println();

        // Access element at index 2
        System.out.println("Element at index 2: " + list.at(2));

        // Remove element at index 2
        System.out.println("Removing element at index 2");
        list.remove(2);
        System.out.print("List after removal: ");
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.at(i) + " ");
        }
        System.out.println();

        // Filter even numbers
        System.out.println("Filtering even numbers:");
        LinkedList<Integer> evens = (LinkedList<Integer>) list.filter(e -> e % 2 == 0);
        System.out.print("Evens: ");
        for (int i = 0; i < evens.size(); i++) {
            System.out.print(evens.at(i) + " ");
        }
        System.out.println();

        // Map to squares
        System.out.println("Mapping to squares:");
        LinkedList<Integer> squares = (LinkedList<Integer>) list.map(e -> e * e);
        System.out.print("Squares: ");
        for (int i = 0; i < squares.size(); i++) {
            System.out.print(squares.at(i) + " ");
        }
        System.out.println();

        // Reduce to sum
        int sum = list.reduce(acc -> elem -> acc + elem, 0);
        System.out.println("Sum of elements: " + sum);

        // Index of existing element
        Optional<Integer> idx = list.indexOf(e -> e == 4);
        if (idx.isPresent()) {
            System.out.println("Index of 4: " + idx.get());
        } else {
            System.out.println("4 not found");
        }

        // Index of non-existing element
        Optional<Integer> missing = list.indexOf(e -> e == 100);
        if (missing.isPresent()) {
            System.out.println("Index of 100: " + missing.get());
        } else {
            System.out.println("100 not found");
        }
    }
} 

Task1,2

Task1

Java

/**
 * Implement a function that returns the maximum value of a non-empty array of integer values. 
 * The implementation must be done in C++, Java, and Python.
 */

public class Task1 {

    public static int maximum(int[] values) {
        assert(values.length > 0);
        int max = values[0];
        for (int i = 1; i < values.length; i++) {
            if (values[i] > max) {
                max = values[i];
            }
        }
        return max;
    }

    private static String toString(int[] values) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < values.length; i++) {
            sb.append(values[i]);
            if (i + 1 < values.length) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public static void main(String[] args) {
        int values[] = new int[args.length];
        int i = 0;
        for (String arg : args) {
            values[i++] = Integer.valueOf(arg);
        }
        System.out.print("The maximum value of " + toString(values));
        System.out.println(" is: " + maximum(values));
    }

}

Python

"""
Implement a function that returns the maximum value of a non-empty array of integer values. 
The implementation must be done in C++, Java, and Python.
"""

def maxOfArray(arr : list[int]) -> int:
    assert(len(values) > 0)
    max: int = values[0]
    for value in values[1:]:
        if value > max:
            max = value
    return max

if __name__ == "__main__":
    import sys
    assert(len(sys.argv) > 1)
    values: list[int] = []
    for argv in sys.argv[1:]:
        values.append(int(argv))
    print("The maximum value of {} is: {}".format(values, maximum(values)))
    string_values = ["Can", "I", "do", "this?"]
    print("The maximum value of {} is: {}".format(string_values, maximum(string_values)))
    tuples_values = [("Is", 1), ("Derp", 42), ("a", 2), ("cool", 3), ("number?", 4)]
    print("The maximum value of {} is: {}".format(tuples_values, maximum(tuples_values)))

C++

/**
 * Implement a function that returns the maximum value of a non-empty array of integer values. 
 * The implementation must be done in C++, Java, and Python.
 */

#include <iostream>
#include <cassert>

int maximum(const int size, int values[]) {
    assert(size > 0);
    int max = values[0];
    for (int i = 1; i < size; i++) {
        if (values[i] > max) {
            max = values[i];
        }
    }
    return max;
}

void printArray(const int size, int values[]) {
    std::cout << "[";
    for (int i = 0; i < size; i++) {
        std::cout << values[i];
        if (i + 1 < size) {
            std::cout << ", ";
        }
    }
    std::cout << "]";
}

int main(const int argc, const char ** const argv) {
    assert(argc > 1);
    int size = argc - 1;
    int values[size];
    for (int i = 1; i < argc; i++) {
        std::string arg = std::string(argv[i]);
        values[i - 1] = std::stoi(arg);
    }
    std::cout << "The maximum value of ";
    printArray(size, values);
    std::cout << " is: " << maximum(size, values) << std::endl;
    return 0;
}

Task2

Java

/**
 *Implement a function that returns the maximum value 
 * of a non-empty generic array of values with type T
 */
import java.util.function.BiFunction;

public class Task2 {

    public static <T> T maximum_f(T[] values, BiFunction<T, T, T> fmax) {
        assert(values.length > 0);
        T max = values[0];
        for (int i = 1; i < values.length; i++) {
            max = fmax.apply(max, values[i]);
        }
        return max;
    }

    public static <T extends Comparable<? super T>> T maximum_c(T[] values) {
        //<T extends Comparable<? super T>> - More flexible
        //Allows T to implement Comparable for itself OR any of its supertypes
        //Uses a "lower bounded wildcard" (? super T)
        //Also you can use Comparable<T> instead of Comparable<? super T>
        assert(values.length > 0);
        T max = values[0];
        for (int i = 1; i < values.length; i++) {
            if (values[i].compareTo(max) > 0) {
                max = values[i];
            }
        }
        return max;
    }

    private static <T> String toString(T[] values) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < values.length; i++) {
            sb.append(String.valueOf(values[i]));
            if (i + 1 < values.length) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    public static void main(String[] args) {
        Integer values[] = new Integer[args.length];
        int i = 0;
        for (String arg : args) {
            values[i++] = Integer.valueOf(arg);
        }
        BiFunction<Integer, Integer, Integer> int_max = (Integer a, Integer b) -> {return a > b? a:b;};
        System.out.print("The maximum value of (using a function) " + toString(values));
        System.out.println(" is: " + maximum_f(values, int_max));

        System.out.print("The maximum value of (using Comparable) " + toString(values));
        System.out.println(" is: " + maximum_c(values));
    }


}

Python

"""
Implement a function that returns the maximum value 
of a non-empty generic array of values with type T
"""
from typing import TypeVar
T = TypeVar("T")

def maxOfArray(arr : list[T]) -> T:
    max = arr[0]
    for i in arr:
        if(i > max):
            max = i
    return max

if __name__ == "__main__":
    test_array = [3, 7, 2, 9, 1, 5]
    print(f"Array: {test_array}")

    max_value = maxOfArray(test_array)
    print(f"Maximum value: {max_value}")

    # Test with strings
    string_array = ["apple", "zebra", "banana", "cherry"]
    print(f"String array: {string_array}")
    max_string = maxOfArray(string_array)
    print(f"Maximum string: {max_string}")

C++

/**
 *Implement a function that returns the maximum value 
 * of a non-empty generic array of values with type T
 */

#include <iostream>
#include <cassert>

class Person {
    private:
        std::string name;
        int id;
    public:
        Person(): name("John"), id(0) {}
        Person(std::string name, int id): name(name), id(id) {}
        Person(const Person& other) {
            this->name = other.name;
            this->id = other.id;
        }
        ~Person() {}
        int getId() const {
            return id;
        }
        int comparesTo(Person other) {
            return this->id - other.id;
        }

    friend std::ostream& operator<<(std::ostream& os, const Person& person);
//friend keyword allows these functions to access private/protected members of the Person class
//std::ostream& is a reference to an output stream object 
    friend bool operator>(const Person& a, const Person& b) {
//With &. No copying - you work directly with the original object, faster and more memory efficient
        return a.getId() > b.getId();
    }
};

std::ostream& operator<<(std::ostream& os, const Person& person) {
    os << "Person(" << person.id << ", " << person.name << ")";
    return os;
}

template<typename T>
T maximum_t(const int size, T values[]) {
    assert(size > 0);
    T max = values[0];
    for (int i = 1; i < size; i++) {
        if (values[i] > max) {
            max = values[i];
        }
    }
    return max;
}

/////////////////////////////////////////////////////

template<typename T>
using t_max = T (*)(T, T);

int max(int a, int b) {
    return a > b? a : b;
}

template<typename T>
T maximum_f(const int size, T values[], t_max<T> max_function) {
    assert(size > 0);
    T max = values[0];
    for (int i = 1; i < size; i++) {
        max = max_function(max, values[i]);
    }
    return max;
}
/////////////////////////////////////////////////////
template<typename T>
concept Comparable = requires(T a, T b) {
    {a.comparesTo(b)} -> std::same_as<int>;
};

template<Comparable T>
T maximum_c(const int size, T values[]) {
    assert(size > 0);
    T max = values[0];
    for (int i = 1; i < size; i++) {
        if (values[i].comparesTo(max) > 0) {
            max = values[i];
        }
    }
    return max;
}

template<typename T>
void printArray(const int size, T values[]) {
    std::cout << "[";
    for (int i = 0; i < size; i++) {
        std::cout << values[i];
        if (i + 1 < size) {
            std::cout << ", ";
        }
    }
    std::cout << "]";
}

int main(const int argc, const char ** const argv) {
    assert(argc > 1);
    int size = argc - 1;
    int values[size];
    for (int i = 1; i < argc; i++) {
        std::string arg = std::string(argv[i]);
        values[i - 1] = std::stoi(arg);
    }
    std::cout << "The maximum value of (using template and >) ";
    printArray(size, values);
    std::cout << " is: " << maximum_t<int>(size, values) << std::endl;

    std::cout << "The maximum value of (using a max function) ";
    printArray(size, values);
    std::cout << " is: " << maximum_f<int>(size, values, max) << std::endl;

    // std::cout << "The maximum value of (using Comparable concept) ";
    // printArray(size, values);
    // std::cout << " is: " << maximum_c<int>(size, values, max) << std::endl;

    Person persons[] = {Person("A", 1), Person("B", 2), Person("C", 3)};
    std::cout << "The maximum value of (using template and >) ";
    printArray(3, persons);
    std::cout << " is: " << maximum_t<Person>(3, persons) << std::endl;

    std::cout << "The maximum value of (using Comparable concept) ";
    printArray(3, persons);
    std::cout << " is: " << maximum_c<Person>(3, persons) << std::endl;
    return 0;
}

Task3,4

Task3

Java

/**
 * Implement a function that returns the most repeated value 
 * on a non-empty array of integer values.
 */
public class Task3 {

    public static int maxIndexOfArray(int arr[]) {
        int maxIndex = 0;
        int size = arr.length;
        for(int i = 0; i < size; i++) {
            if(arr[i] > arr[maxIndex])
                maxIndex = i;
        }
        return maxIndex;
    }

    public static int repeatedCount(int arr[]) {
        int currentVar;
        int size = arr.length;
        int count[] = new int[size];//Note this
        for(int i = 0; i < size; i++) {
            int times = 0;
            currentVar = arr[i];
            for(int j = 0; j< size; j++) {
                if(currentVar == arr[j])
                    times++;
            }
            count[i] = times;
        }
        return arr[maxIndexOfArray(count)];
    }

    public static void main(String[] args) {
        int[] testArray = {1, 3, 2, 3, 4, 3, 2, 1, 3};

        System.out.print("Array: ");
        for(int num : testArray) {
            System.out.print(num + " ");
        }
        System.out.println();

        int mostRepeated = repeatedCount(testArray);
        System.out.println("Most repeated value: " + mostRepeated);
    }
}

Python

"""
Implement a function that returns the most repeated value 
on a non-empty array of integer values.
"""

def maxIndexOfArray(arr : list[int]) -> int:
    maxIndex = 0
    size = len(arr)
    for i in range(len(arr)):
        if(arr[i] > arr[maxIndex]):
            maxIndex = i
    return maxIndex

def repeatedCount(arr : list[int]) -> int:
    size = len(arr)
    count = [0] * size #Note this
    for i in range(size):
        times = 0
        currentVar = arr[i]
        for j in range(size):
            if currentVar == arr[j]:
                times += 1
        count[i] = times
    return arr[maxIndexOfArray(count)]

if __name__ == "__main__":
    test_array = [1, 3, 2, 3, 4, 3, 2, 1, 3]
    print(f"Array: {test_array}")

    most_repeated = repeatedCount(test_array)
    print(f"Most repeated value: {most_repeated}")

C++

/**
 * Implement a function that returns the most repeated value 
 * on a non-empty array of integer values.
 */

#include <iostream>
using namespace std;

int maxIndexOfArray(int arr[], int size) {
    int maxIndex = 0;
    for(int i = 0; i < size; i++) {
        if(arr[i] > arr[maxIndex])
            maxIndex = i;
    }
    return maxIndex;
}

int repeatedCount(int arr[], int size) {
    int currentVar;
    int count[size];
    for(int i = 0; i < size; i++) {
        int times = 0;
        currentVar = arr[i];
        for(int j = 0; j< size; j++) {
            if(currentVar == arr[j])
                times++;
        }
        count[i] = times;
    }
    return arr[maxIndexOfArray(count, size)];
}

int main() {
    int testArray[] = {1, 3, 2, 3, 4, 3, 2, 1, 3};
    int size = sizeof(testArray) / sizeof(testArray[0]);

    cout << "Array: ";
    for(int i = 0; i < size; i++) {
        cout << testArray[i] << " ";
    }
    cout << endl;

    int mostRepeated = repeatedCount(testArray, size);
    cout << "Most repeated value: " << mostRepeated << endl;

    return 0;
}

Task4

Java

/**
 * Implement a function that returns the most repeated value 
 * on a non-empty generic array of values with type T
 */
public class Task4 {

    public static <T extends Comparable<T>> T repeatedCount(T[] arr) {
        T currentVar;
        int size = arr.length;
        int count[] = new int[size];//Note this
        for(int i = 0; i < size; i++) {
            int times = 0;
            currentVar = arr[i];
            for(int j = 0; j< size; j++) {
                if(currentVar.compareTo(arr[j]) == 0)
                    times++;
            }
            count[i] = times;
        }
        return arr[maxIndexOfArray(count)];
    }

    public static int maxIndexOfArray(int[] arr) {
        int maxIndex = 0;
        int size = arr.length;
        for(int i = 0; i < size; i++) {
            if(arr[i] > (arr[maxIndex]))
                maxIndex = i;
        }
        return maxIndex;
    }

    public static void main(String[] args) {
        // Test with integers
        Integer[] intArray = {1, 3, 2, 3, 4, 3, 2, 1, 3};
        System.out.print("Integer array: ");
        for(Integer num : intArray) {
            System.out.print(num + " ");
        }
        System.out.println();
        Integer mostRepeated = repeatedCount(intArray);
        System.out.println("Most repeated integer: " + mostRepeated);

        // Test with strings
        String[] stringArray = {"apple", "banana", "apple", "cherry", "apple", "banana"};
        System.out.print("String array: ");
        for(String str : stringArray) {
            System.out.print(str + " ");
        }
        System.out.println();
        String mostRepeatedString = repeatedCount(stringArray);
        System.out.println("Most repeated string: " + mostRepeatedString);
    }
}

Python

"""
Implement a function that returns the most repeated value 
on a non-empty generic array of values with type T
"""
from typing import TypeVar
T = TypeVar("T")

def maxIndexOfArray(arr : list[int]) -> int:
    maxIndex = 0
    size = len(arr)
    for i in range(len(arr)):
        if(arr[i] > arr[maxIndex]):
            maxIndex = i
    return maxIndex

def repeatedCount(arr : list[T]) -> T:
    size = len(arr)
    count = [0] * size #Note this
    for i in range(size):
        times = 0
        currentVar = arr[i]
        for j in range(size):
            if currentVar == arr[j]:
                times += 1
        count[i] = times
    return arr[maxIndexOfArray(count)]

if __name__ == "__main__":
    # Test with integers
    test_array = [1, 3, 2, 3, 4, 3, 2, 1, 3]
    print(f"Integer array: {test_array}")
    most_repeated = repeatedCount(test_array)
    print(f"Most repeated value: {most_repeated}")

    # Test with strings
    string_array = ["apple", "banana", "apple", "cherry", "apple", "banana"]
    print(f"String array: {string_array}")
    most_repeated_string = repeatedCount(string_array)
    print(f"Most repeated string: {most_repeated_string}")

C++

/**Implement a function that returns the most repeated value 
 * on a non-empty generic array of values with type T
 */ 
#include <concepts>
#include <iostream>
using namespace std;

template <typename T>
concept Comparable = requires(T a, T b) {
    { a.compares_to(b) } -> std::same_as<int>;
};

template<Comparable T>
int comparing(T a, T b) {
    return a.compares_to(b);
}

int maxIndexOfArray(int arr[], int size) {
    int maxIndex = 0;
    for(int i = 0; i < size; i++) {
        if(arr[i] > arr[maxIndex])
            maxIndex = i;
    }
    return maxIndex;
}

template<Comparable T>
T repeatedCount(T arr[], int size) {
    T currentVar;
    int count[size];
    for(int i = 0; i < size; i++) {
        int times = 0;
        currentVar = arr[i];
        for(int j = 0; j < size; j++) {
            if(comparing(currentVar, arr[j]) == 0)
                times++;
        }
        count[i] = times;
    }
    return arr[maxIndexOfArray(count, size)];
}

// Simple test class that satisfies Comparable concept
class TestValue {
public:
    int value;
    TestValue(int v) : value(v) {}

    int compares_to(const TestValue& other) const {
        if (value > other.value) return 1;
        if (value < other.value) return -1;
        return 0;
    }

    friend ostream& operator<<(ostream& os, const TestValue& tv) {
        os << tv.value;
        return os;
    }
};

int main() {
    TestValue testArray[] = {TestValue(1), TestValue(3), TestValue(2), TestValue(3), TestValue(4), TestValue(3), TestValue(2), TestValue(1), TestValue(3)};
    int size = sizeof(testArray) / sizeof(testArray[0]);

    cout << "Array: ";
    for(int i = 0; i < size; i++) {
        cout << testArray[i] << " ";
    }
    cout << endl;

    TestValue mostRepeated = repeatedCount(testArray, size);
    cout << "Most repeated value: " << mostRepeated << endl;

    return 0;
}

Task5,6

Task5

Java

/**
 * Implement a function that returns the sum of the values 
 * in an array of integer values.
 */
public class Task9 {

    public static int sumArray(int[] arr) {
        int sum = 0;
        for(int value : arr)
            sum += value;
        return sum;
    }

    public static void main(String[] args) {
        int[] testArray = {1, 2, 3, 4, 5};

        System.out.print("Array: ");
        for(int num : testArray) {
            System.out.print(num + " ");
        }
        System.out.println();

        int sum = sumArray(testArray);
        System.out.println("Sum of array: " + sum);
    }
}

Python

"""
Implement a function that returns the sum of the values 
in an array of integer values.
"""

def sum_array(arr):
    #if len(arr) == 0:
    #    print("Array is empty")
    total = 0
    for value in arr:
        total += value
    return total

if __name__ == "__main__":
    test_array = [1, 2, 3, 4, 5]
    print(f"Array: {test_array}")

    total = sum_array(test_array)
    print(f"Sum of array: {total}")

C++

/**
 * Implement a function that returns the sum of the values 
 * in an array of integer values.
 */

#include <iostream>
using namespace std;

int sumArray(int arr[], int size) {
    int sum = 0;
    for(int i = 0; i < size; i++)
        sum += arr[i];
    return sum;
}

int main() {
    int testArray[] = {1, 2, 3, 4, 5};
    int size = sizeof(testArray) / sizeof(testArray[0]);

    cout << "Array: ";
    for(int i = 0; i < size; i++) {
        cout << testArray[i] << " ";
    }
    cout << endl;

    int sum = sumArray(testArray, size);
    cout << "Sum of array: " << sum << endl;

    return 0;
}

Task6

Java

/**
 * Implement a function that returns the sum of the values 
 * in a generic array of values with type T
 */
public class Task10 {

    public static <T extends Number> double sum(T[] array) {
        double result = 0;
        for (T value : array) {
            result += value.doubleValue();
        }
        return result;
    }

    public static void main(String[] args) {
        // Test with integers
        Integer[] intArray = {1, 2, 3, 4, 5};
        System.out.print("Integer array: ");
        for(Integer num : intArray) {
            System.out.print(num + " ");
        }
        System.out.println();
        double intSum = sum(intArray);
        System.out.println("Sum of integers: " + intSum);

        // Test with doubles
        Double[] doubleArray = {1.5, 2.5, 3.5, 4.5, 5.5};
        System.out.print("Double array: ");
        for(Double num : doubleArray) {
            System.out.print(num + " ");
        }
        System.out.println();
        double doubleSum = sum(doubleArray);
        System.out.println("Sum of doubles: " + doubleSum);
    }
}

Python

"""
Implement a function that returns the sum of the values 
in a generic array of values with type T.
"""

from typing import TypeVar, List
from numbers import Number

T = TypeVar('T', bound = Number)

def sum_array(arr: List[T]) -> T:
    if not arr:
        raise ValueError("Cannot sum an empty array")

    total = arr[0]  # Initialize with first element to maintain type T
    for value in arr[1:]:
        total += value
    return total

if __name__ == "__main__":
    # Test with integers
    int_array = [1, 2, 3, 4, 5]
    print(f"Integer array: {int_array}")
    int_sum = sum_array(int_array)
    print(f"Sum of integers: {int_sum}")

    # Test with floats
    float_array = [1.5, 2.5, 3.5, 4.5, 5.5]
    print(f"Float array: {float_array}")
    float_sum = sum_array(float_array)
    print(f"Sum of floats: {float_sum}")

C++

/**
 * Implement a function that returns the sum of the values 
 * in a generic array of values with type T
 */

#include <iostream>
using namespace std;

template<typename T>
T sumArray(T arr[], int size) {
    T sum = T(); // Initialize sum to default value of type T (0 for numeric types)
    for(int i = 0; i < size; i++)
        sum += arr[i];
    return sum;
}

int main() {
    // Test with integers
    int intArray[] = {1, 2, 3, 4, 5};
    int intSize = sizeof(intArray) / sizeof(intArray[0]);

    cout << "Integer array: ";
    for(int i = 0; i < intSize; i++) {
        cout << intArray[i] << " ";
    }
    cout << endl;

    int intSum = sumArray(intArray, intSize);
    cout << "Sum of integers: " << intSum << endl;

    // Test with doubles
    double doubleArray[] = {1.5, 2.5, 3.5, 4.5, 5.5};
    int doubleSize = sizeof(doubleArray) / sizeof(doubleArray[0]);

    cout << "Double array: ";
    for(int i = 0; i < doubleSize; i++) {
        cout << doubleArray[i] << " ";
    }
    cout << endl;

    double doubleSum = sumArray(doubleArray, doubleSize);
    cout << "Sum of doubles: " << doubleSum << endl;

    return 0;
}
  1. Is there any discernible difference between the implementations, i.e.: is there a language that makes
    the implementation easier or more difficult?

    • Java: Requires explicit type constraints (Comparable or BiFunction). More verbose but type-safe.
    • Python: Simplest implementation due to duck typing. No explicit generics needed at runtime.
    • C++ : Most complex due to template syntax, operator overloading, and concepts. Offers compile-time safety but requires more boilerplate.

    Ease Ranking: Python > Java > C++

  2. Is there any feature or lack of a feature in one or more of the three languages that prevents to
    implement a proper solution?

    • Java: No operator overloading forces use of Comparable or functional interfaces.
    • Python: No compile-time type checks (runtime errors possible).
    • C++ : Concepts require C++20. Custom types need explicit operator/function definitions.

    All languages support a proper solution, but with different trade-offs.

  3. Is there any requirement on the values to be able to implement the solution? Could you write this
    requirement as a checkable restriction? How? You don’t need to implement it, just provide description
    on how

    Core Requirement: Values must be comparable - they need to support some form of ordering relationship.

    How to express this as checkable restrictions:

    Python (Runtime checking):

    from typing import Protocol
    
    class Comparable(Protocol):
        def __gt__(self, other) -> bool: ...
    
    def maxOfArray(arr: list[Comparable]) -> Comparable:
        # Implementation remains the same
    

    Java (Compile-time bounded generics):

    // Already shown in your code:
    public static <T extends Comparable<? super T>> T maximum_c(T[] values)
    
    // Or with custom comparator:
    public static <T> T maximum_f(T[] values, BiFunction<T, T, T> fmax)
    

    C++ (Compile-time concepts - most expressive):

    // Already shown in your code:
    template<typename T>
    concept Comparable = requires(T a, T b) {
        {a.comparesTo(b)} -> std::same_as<int>;
    };
    
    // Or using standard operators:
    template<typename T>
    concept Orderable = requires(T a, T b) {
        {a > b} -> std::same_as<bool>;
    };
    

Task 6 What is the purpose of using Concepts in C++?

Concepts in C++ serve several crucial purposes:

  1. Compile-time Constraints: Ensure template parameters meet specific requirements before instantiation

  2. Better Error Messages: Instead of cryptic template errors, you get clear constraint violations

  3. Self-documenting Code: Concepts make template requirements explicit in the interface

  4. Overload Resolution: Enable function overloading based on concept satisfaction

  5. Template Specialization: Allow different implementations for different concept-satisfying types

Task 7 Can we pass functions as arguments in any of the languages we saw (Java, C++, Python)? Is there any
meaning difference between how this is done in the three languages

Yes, all three languages support passing functions as arguments, but with different mechanisms:

Java - Function Objects/Lambda Expressions:

BiFunction<Integer, Integer, Integer> int_max = (a, b) -> a > b ? a : b;
maximum_f(values, int_max);
  • Uses functional interfaces (BiFunction)
  • Lambda expressions or method references
  • Type-safe with generics

C++ - Function Pointers/Templates:

template<typename T>
using t_max = T (*)(T, T);  // Function pointer type alias

int max(int a, int b) { return a > b ? a : b; }
maximum_f<int>(size, values, max);
  • Function pointers (shown)
  • Function objects/functors
  • Lambda expressions (C++11+)
  • Templates can accept any callable

Python - First-class Functions:

def custom_max(a, b):
    return a if a > b else b

def maxOfArray(arr, compare_func=lambda a, b: a if a > b else b):
    # Could be implemented to use compare_func
  • Functions are first-class objects
  • Can pass functions directly
  • Lambda expressions
  • Most flexible - any callable object works

C++ constructor Example

#include <iostream>
#include <cassert>

class OptionalInt {
    private:
        int * value = nullptr;

    public:

        OptionalInt() {
            this->value = nullptr;
        }

        OptionalInt(int value) {
            this->value = new int(value);
        }

        OptionalInt(const OptionalInt& other) {
            if (this->is_present()) {
                delete this->value;
            }
            if (other.is_present()) {
                this->value = new int(other.get_value());
            } else {
                this->value = nullptr;
            }
        }

        bool is_present() const {
            return this->value != nullptr;
        }

        int get_value() const{
            assert(is_present());
            return *this->value;
        }

        ~OptionalInt() {
            if (is_present()) {
                delete value;
            }
        }

        friend std::ostream& operator<<(std::ostream& out, OptionalInt& optional);

};

std::ostream& operator<<(std::ostream& out, OptionalInt& optional) {
    //optional cannot be null, the & in here is stating that the argument is passed as a reference
    if (optional.is_present()) {
        out << "Optional(" << optional.get_value() << ")";
    } else {
        out << "Empty";
    }
    return out;
}

static OptionalInt maximum(int size, int values[]);
static int parse_argument(const char * const arg);

int main(const int argc, const char ** const argv) {
    int values_size = argc - 1;
    int values[values_size];
    for (int i = 1; i < argc; i++) {
        values[i - 1] = parse_argument(argv[i]);
    }
    OptionalInt maximum_value = maximum(values_size, values);
    std::cout << "The maximum value found was: " << maximum_value << std::endl;
    return 0;
}

static OptionalInt maximum(int size, int values[]) {
    if (size == 0) {
        OptionalInt empty = OptionalInt();
        return empty;
    }
    int max = values[0];
    for (int i = 1; i < size; i++) {
        int current = values[i];
        if (current > max) {
            max = current;
        }
    }
    return OptionalInt(max);
}

static int parse_argument(const char * const arg) {
    int num;
    try {
        std::string int_str = std::string(arg);
        num = std::stoi(int_str);
    } catch (const std::invalid_argument& e) {
        std::cerr << "Invalid argument: " << e.what() << std::endl;
    } catch (const std::out_of_range& e) {
        std::cerr << "Out of range: " << e.what() << std::endl;
    }
    return num;
}

Exercise 13

Java

package Task1_2;

import java.util.ArrayList;

public class Dictionary<K, V> {
    private ArrayList<Entry<K, V>> entries;

    private static class Entry<K, V> {
        final K key;
        V value;

        Entry(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    public Dictionary() {
        this.entries = new ArrayList<>();
    }

    /**
     * Puts a key-value pair into the dictionary.
     * If the key already exists, updates the value.
     * @param key the key
     * @param value the value
     */
    public void put(K key, V value) {
        for (Entry<K, V> entry : entries) {
            if (entry.key.equals(key)) {
                entry.value = value;
                return;
            }
        }
        entries.add(new Entry<>(key, value));
    }

    /**
     * Gets the value associated with the given key.
     * Returns Optional.empty() if the key doesn't exist.
     * @param key the key to look up
     * @return Optional containing the value if found, empty otherwise
     */
    public Optional<V> get(K key) {
        for (Entry<K, V> entry : entries) {
            if (entry.key.equals(key)) {
                return Optional.of(entry.value);
            }
        }
        return Optional.empty();
    }

    /**
     * Removes the key-value pair for the given key.
     * @param key the key to remove
     * @return true if the key was found and removed, false otherwise
     */
    public boolean remove(K key) {
        for (int i = 0; i < entries.size(); i++) {
            if (entries.get(i).key.equals(key)) {
                entries.remove(i);
                return true;
            }
        }
        return false;
    }

    /**
     * Checks if the dictionary contains the given key.
     * @param key the key to check
     * @return true if the key exists, false otherwise
     */
    public boolean containsKey(K key) {
        for (Entry<K, V> entry : entries) {
            if (entry.key.equals(key)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the number of key-value pairs in the dictionary.
     * @return the size of the dictionary
     */
    public int size() {
        return entries.size();
    }

    /**
     * Checks if the dictionary is empty.
     * @return true if the dictionary is empty, false otherwise
     */
    public boolean isEmpty() {
        return entries.isEmpty();
    }

    /**
     * Removes all key-value pairs from the dictionary.
     */
    public void clear() {
        entries.clear();
    }

    /**
     * Returns a string representation of the dictionary.
     * @return string representation showing all key-value pairs
     */
    @Override
    public String toString() {
        if (isEmpty()) {
            return "{}";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("{");
        for (int i = 0; i < entries.size(); i++) {
            Entry<K, V> entry = entries.get(i);
            sb.append(entry.key).append("=").append(entry.value);
            if (i < entries.size() - 1) {
                sb.append(", ");
            }
        }
        sb.append("}");
        return sb.toString();
    }
} 

Python

"""
Implement in both Python and C++ a Dictionary class that maps values of 
a generic type K to a generic type V. 
Consider the case where a user wants to get the value for a key 
that doesn’t exist
"""

from typing import TypeVar, Generic, Dict, Optional, List, Tuple

K = TypeVar('K')
V = TypeVar('V')

class Dictionary(Generic[K, V]):
    """
    A generic dictionary mapping keys of type K to values of type V.
    """
    def __init__(self) -> None:
        self._data: Dict[K, V] = {}

    def add(self, key: K, value: V) -> None:
        """
        Add a key-value pair. Raises KeyError if key already exists.
        """
        if key in self._data:
            raise KeyError(f"Key {key} already exists.")
        self._data[key] = value

    def get(self, key: K, default: Optional[V] = None) -> V:
        """
        Get the value for key. If key does not exist:
          - If default provided, return default
          - Otherwise, raise KeyError
        """
        if key in self._data:
            return self._data[key]
        if default is not None:
            return default
        raise KeyError(f"Key {key} does not exist.")

    def remove(self, key: K) -> None:
        """
        Remove the key. Raises KeyError if key does not exist.
        """
        if key not in self._data:
            raise KeyError(f"Key {key} does not exist.")
        del self._data[key]

    def contains(self, key: K) -> bool:
        """
        Check if the key exists in dictionary.
        """
        return key in self._data

    def keys(self) -> List[K]:
        return list(self._data.keys())

    def values(self) -> List[V]:
        return list(self._data.values())

    def items(self) -> List[Tuple[K, V]]:
        return list(self._data.items())

    def __len__(self) -> int:
        return len(self._data)

    def __getitem__(self, key: K) -> V:
        return self.get(key)

    def __setitem__(self, key: K, value: V) -> None:
        self._data[key] = value

C++

/*
Implement in both Python and C++ a Dictionary class that maps values of 
a generic type K to a generic type V. 
Consider the case where a user wants to get the value for a key 
that doesn’t exist
*/

#include <map>
#include <iostream>
#include <string>

template<typename K, typename V>
class Dictionary {
private:
    std::map<K, V> data;

public:
    // Insert or update a key-value pair
    void put(const K& key, const V& value) {
        data[key] = value;
    }

    // Get value by key, returns pointer to value or nullptr if not found
    // This is safe way to handle non-existing keys
    V* get(const K& key) {
        auto it = data.find(key);
        if (it != data.end()) {
            return &(it->second);
        }
        return nullptr; // Key doesn't exist
    }

    // Get value with a default value if key doesn't exist
    V getValue(const K& key, const V& defaultValue) const {
        auto it = data.find(key);
        if (it != data.end()) {
            return it->second;
        }
        return defaultValue;
    }

    // Check if key exists in the dictionary
    bool contains(const K& key) const {
        return data.find(key) != data.end();
    }

    // Remove a key-value pair
    bool remove(const K& key) {
        return data.erase(key) > 0;
    }

    // Get the number of key-value pairs
    size_t size() const {
        return data.size();
    }

    // Check if dictionary is empty
    bool empty() const {
        return data.empty();
    }

    // Print all key-value pairs (for demonstration)
    void printAll() const {
        std::cout << "Dictionary contents:\n";
        for (const auto& pair : data) {
            std::cout << "Key: " << pair.first << ", Value: " << pair.second << "\n";
        }
    }
};

// Example usage and demonstration
int main() {
    // Create a dictionary that maps strings to integers
    Dictionary<std::string, int> ages;

    // Add some data
    ages.put("Alice", 25);
    ages.put("Bob", 30);
    ages.put("Charlie", 35);

    std::cout << "=== Dictionary Demo ===\n";
    ages.printAll();
    std::cout << "\n";

    // Safe way to get values - using pointer
    std::cout << "Getting values safely with pointers:\n";
    int* aliceAge = ages.get("Alice");
    if (aliceAge != nullptr) {
        std::cout << "Alice's age: " << *aliceAge << "\n";
    }

    int* davidAge = ages.get("David"); // This key doesn't exist
    if (davidAge != nullptr) {
        std::cout << "David's age: " << *davidAge << "\n";
    } else {
        std::cout << "David not found in dictionary\n";
    }

    // Using default values
    std::cout << "\nUsing default values:\n";
    int bobAge = ages.getValue("Bob", 0);
    int eveAge = ages.getValue("Eve", 0); // Doesn't exist, will return 0
    std::cout << "Bob's age: " << bobAge << "\n";
    std::cout << "Eve's age (default): " << eveAge << "\n";

    // Check if keys exist
    std::cout << "\nChecking if keys exist:\n";
    std::cout << "Contains Alice? " << (ages.contains("Alice") ? "Yes" : "No") << "\n";
    std::cout << "Contains Frank? " << (ages.contains("Frank") ? "Yes" : "No") << "\n";

    // Dictionary with different types
    std::cout << "\n=== Different Types Demo ===\n";
    Dictionary<int, std::string> names;
    names.put(1, "One");
    names.put(2, "Two");
    names.put(3, "Three");

    std::string* name = names.get(2);
    if (name != nullptr) {
        std::cout << "Number 2 is: " << *name << "\n";
    }

    std::string unknownName = names.getValue(5, "Unknown");
    std::cout << "Number 5 is: " << unknownName << "\n";

    return 0;
}