NivaarExam PrepOfficial exam papers ↗

19-Soft-B17 Data Visualization · December 2014

Question 2 of 10

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

04-Soft-B17, Programming Language Paradigm — National Exams, December 2014 (3 hours, open book, 10 questions of equal value, essay-format answers).

Reference texts: Sebesta, Concepts of Programming Languages, 12th ed. (object-oriented language design, subtyping, functional programming, exception handling, lambda expressions); Sommerville, Software Engineering, 10th ed. (object-oriented design, modularity); Gamma et al. (GoF), Design Patterns, 1st ed. (composition-over-inheritance, Liskov Substitution Principle in practice).

Check: this paper's printed course title and all ten questions are exclusively about object-oriented and functional programming-language concepts (classes, subtyping, overriding/overloading, exceptions, functional vs. procedural style, actor model, lambda expressions, immutability) — there is no data-visualization content anywhere in the paper. This solution follows the exam as printed ("04-SOFT-B17: Programming Language Paradigm").

Question 2 (10%)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Taking Java as the example language: every object inherits a default equals(Object o) method from the root Object class, and by default that method is defined as this == o — that is, reference (identity) equality. Two distinct objects that hold exactly the same field values are, by default, considered unequal unless the class author overrides equals() to compare state instead of identity. This mirrors the general OO default: without programmer intervention, "equal" means "the same object in memory," not "objects that look the same." A class must explicitly opt into value (structural) equality by overriding equals() to compare the objects' relevant fields, and (in Java specifically) must also override the paired hashCode() method so that equal objects still produce equal hash codes — otherwise the object silently breaks when used as a key in a hash-based collection such as HashMap or HashSet, since those collections consult hashCode() to find the bucket before ever calling equals().

Deciding what "equal" should mean for a class requires several considerations. First, which fields participate: transient or purely derived state (a cached computation, an internal lock object) usually should not affect equality, while fields that define the object's identity/value should. Second, shallow vs. deep comparison: if a field is itself a reference type (e.g., a list or another object), the equality method must decide whether two containers are equal only when they hold the identical inner objects (shallow) or when their inner objects are themselves equal by value (deep) — getting this wrong is a common source of surprising bugs when equality is used with mutable collections. Third, mutability: if a field used in equals() can change after the object has been placed in a hash-based collection, the object's hash bucket becomes stale and lookups silently fail; classes intended for use as hash keys are therefore usually made immutable (or exclude mutable fields from equality). Fourth, whether equality should be type-strict (an instance of a subclass can never equal an instance of the base class, even with identical fields) or based on a shared interface — type-strict is the usual safe default because it avoids violating the symmetry property below when a subclass adds fields.

A correct equality method must satisfy the standard mathematical properties of an equivalence relation, which the Java contract states explicitly: reflexive (x.equals(x) is always true), symmetric (x.equals(y) iff y.equals(x)), transitive (if x.equals(y) and y.equals(z) then x.equals(z)), consistent (repeated calls return the same result provided no relevant field changes), and non-null (x.equals(null) must return false rather than throw). A common way symmetry is accidentally violated is a subclass that overrides equals() to add its own fields but still returns true when compared against a base-class instance that lacks those fields — the base instance's own (unmodified) equals() would then disagree with the subclass's, breaking the relation.