Abstract class 2026-10-24
An abstract class cannot be instantiated directly and may combine concrete state or behavior with abstract operations that subclasses implement. Concrete object methods can depend on a representation convention that every subclass must maintain. An abstract declaration still has a result type: omitted result types in Scala 2 procedure syntax mean Unit, not an unspecified Boolean query.
For a nonempty string, assign a character its occurrence count divided by the string length. Counts partition the character positions, proving normalization. Empty input has no total count to normalize and needs an explicit alternative contract or rejection. A Scala Char implementation counts UTF-16 code units unless a separate code-point representation is introduced.
Companion class 2026-10-24
In Scala, a class paired with a same-named companion object in the appropriate source context. They can access each other's private members. This permits a companion object to hide implementation-node definitions while the corresponding class creates and manipulates those nodes.[ref]
A parameter position for which implies . In Scala, it is annotated -. A consumer capable of accepting every broad-type value can safely serve a context that supplies only narrower values. Returning a value of that parameter type would generally break this guarantee.
Covariant type parameter 2026-10-24
A parameter position for which implies . In Scala, it is annotated +. An immutable producer can return narrower values where broader values are expected. A method consuming that parameter directly would generally make covariance unsafe, since a widened reference could then receive unsupported inputs.
Dynamic dispatch 2026-10-24
Selection of an instance method implementation using the receiver's runtime type. It operates on the method signature already determined by the language's call typing and overload rules. It does not imply dispatch on every argument's runtime type; in particular, method overloading in Scala normally uses static argument types.
Memento pattern 2026-10-24
A design in which an originator creates an opaque snapshot of its state, a caretaker retains it, and the originator can later restore it. Encapsulation prevents the caretaker from depending on internal state representation. A memento must freeze the relevant state: references to mutable objects can require a deep copy, while immutable values can safely be shared. Scala's access controls and path-dependent types can restrict snapshot construction and associate it with its originating instance.
Method overloading 2026-10-24
Several callable methods share one name but differ in parameter signatures. In ordinary Scala calls, the compiler chooses among applicable alternatives using the receiver and arguments' static types, preferring a uniquely most-specific applicable alternative. Overloading is therefore a different step from method overriding and receiver-based dynamic dispatch.
Method overriding 2026-10-24
A subclass or composed trait supplies an implementation of an inherited method signature. Ordinary instance calls use dynamic dispatch to choose the effective implementation for the receiver, after any overload selection. In Scala, overriding a concrete inherited member requires the override modifier; a qualified super invocation selects the corresponding inherited implementation.
Mixin 2026-10-24
Reusable behavior composed into a host class in object-oriented programming, often through a trait. Scala allows one superclass and several mixed-in traits. Required abstract members let a mixin depend on host capabilities without fixing one concrete superclass; member conflicts and super calls are resolved using the language's linearization rules.
Source paper: released examination archive, member 2018/T/a10098w1.pdf. The original cover identifies the Trinity Term examination of Wednesday 19 June 2019; the archive directory does not determine its year. All eight questions are covered. Code uses Scala 2 syntax.
The first proposed identity can fail even without numerical error because binary fractions have nonunique textual representations. Leading zeroes, optional points and trailing fractional zeroes are normalized differently by a fixed-width output convention. It also fails if the input has more significant bits than Double can preserve, more fractional places than the output buffer can hold, an integer part outside the assumed Int range, or a value that overflows or underflows during decoding. Array identity here must mean equal contents: a newly allocated Scala array is a different software object, so use sameElements rather than reference equality for a content test.
The second identity fails when the stored fractional precision truncates a nonzero bit; with two fractional places, becomes zero. It can also fail outside the finite nonnegative input and integer-conversion assumptions. Within those assumptions, enough fractional positions to encode the finite Double exactly can permit the round trip, but an arbitrary fixed small width does not guarantee it. Every finite Double has a finite binary expansion; saying that a decimal-looking Double necessarily has an infinite binary expansion would confuse the represented number with an exact decimal real.
The source's introductory example is internally inconsistent: the displayed digit string has value , whereas its shortened character array encodes . The conversion rules above follow the actual input digits. Round-trip testing needs an independent value oracle as well as the two compositions, because two mutually consistent but incorrect routines can conceal each other's errors.
Source paper: released examination archive, member 2018/L/a10098w1.pdf. The cover identifies the Long Vacation sitting of Thursday 5 September 2019. That printed identity takes precedence over the archive member's directory name.
The implementations use Scala 2 syntax. Fixed-width results are checked when arbitrary-precision arithmetic is needed internally; the mathematical contracts do not make integer overflow harmless. All eight questions are covered.
Code follows Scala 2 style. Each question uses its own enclosing declarations and the supplied fields; alternative implementations with the same name are separate solutions. Mathematical correctness arguments use exact values unless floating-point arithmetic or machine-range bounds are discussed explicitly.
Count each invocation before delegating, including duplicate insertions, and reset after clearing:
class IntegerSetWithCount extends IntegerSet() {
  private var attempts = BigInt(0)

  override def insert(x: Int): Unit = {
    attempts += 1
    super.insert(x)
  }
  override def clear: Unit = {
    super.clear
    attempts = BigInt(0)
  }
  def getCount: BigInt = attempts
}
The inherited implementation already maintains size; the new counter measures insertion attempts, not successful increases in cardinality. Deletion and popping do not subtract from it. Incrementing before delegation also counts an attempted insertion that subsequently fails a capacity check. Arbitrary-precision arithmetic avoids silently wrapping the historical count, though its arithmetic is not constant-cost for arbitrarily large counts.
As the source supplies no object constructor signature for the concrete set, this code uses a fresh default-constructible IntegerSet, with matching default capacity. Its correct behavior also assumes the base implementation does not internally invoke these overridable operations in a way that interferes with the counter. Part e exhibits that dependency.
Source-signature qualification for the following set implementations: the intended membership query must be declared def contains(x: Int): Boolean. The printed abstract declaration omits its result type; interpreted literally as Scala 2 procedure syntax, it returns Unit. The solutions use the explicit Boolean query contract, and Unit for the two mutators. Parameterless clear is overridden without adding parentheses.[ref]
Instantiate the two type parameters and implement the function object interface:
val square: Fun[Int, Int] = new Fun[Int, Int] {
  override def apply(x: Int): Int = x * x
}
Parametric polymorphism occurs because the generic trait is specialized by choosing its argument and result types. Subtype polymorphism occurs because the anonymous implementing software class is used through a Fun[Int, Int] reference; calls to its apply operation use the object interface contract and dynamic dispatch. Multiplication itself is not the second polymorphism needed for this explanation.
For values whose mathematical squares fit in a signed 32-bit integer, the result is the ordinary square. Outside that range, the supplied integer return type cannot represent every mathematical square, and the multiplication follows Scala integer-overflow behavior. An implementation requiring exact mathematical results for all integer inputs would need a wider result type or an explicit overflow exception.
A function accepting every Base can safely be used where only Derived inputs will be supplied. The reverse direction is unsafe. A Derived argument is already a valid Base argument; restricting the possible callers introduces no new obligation for the function. This is the contravariant input rule of function subtyping.
The printed trait has generic type invariance, so Scala does not directly permit either parameter-changing assignment. The safe behavior can be exposed using an explicit adapter without changing that trait:
def restrictInput(f: Fun[Base, Base]): Fun[Derived, Base] =
  new Fun[Derived, Base] {
    def apply(x: Derived): Base = f(x)
  }
For the unsafe direction, take illustrative classes in which a derived software object has an extra operation:
class Base
class Derived extends Base { def special(): Int = 1 }
val narrow = new Fun[Derived, Base] {
  def apply(x: Derived): Base = { x.special(); x }
}
def broadClient(f: Fun[Base, Base]): Base = f(new Base)
// broadClient(narrow) must be rejected.
If that substitution were accepted, the client could pass an ordinary base software object to code that calls special, which that software object does not support. The rejected call is intentional counterexample code, not a promised compilable application. Variance annotations are needed to make sound direct conversions part of the generic trait's declared subtyping relation.[ref]
Constructing channel implementations, decorators and adapters allocates software objects that hold state and references to other software objects. As configurations and temporary processing chains are replaced, some old software objects become unreachable. A typical Scala program on a managed runtime relies on garbage collection to recycle that storage; otherwise unreclaimed allocation can exhaust the available heap memory.
A reachable wrapper keeps its wrapped component reachable. Sharing a channel among several wrappers can extend its lifetime until all relevant references disappear. Many software objects alone do not imply that collection can free them: if the program deliberately retains every channel, those software objects remain live. The reason garbage collection is useful is repeated allocation combined with changing reachability, not an assumption that the integer-returning apply operation allocates a fresh channel on every call.
The held cover identifies the Long Vacation sitting of 9 September 2021, distinct from the June paper carrying the same formal code. All eight questions and all 39 terminal leaves are answered. Scala snippets use Scala 2.13 style and the supplied interfaces. No Scala compiler is installed in the checking environment: independent models, exact calculations and Java numeric-helper checks are distinguished from native Scala or GUI execution.
Use a finite sequence as abstract state, initially empty. One Scala interface is
trait DoubleEndedQueue {
  def isEmpty: Boolean
  def addLeft(x: Int): Unit
  def getLeft(): Int
  def addRight(x: Int): Unit
  def getRight(): Int
}
The emptiness query has no precondition; its result is and its postcondition is . Adding on the left has no precondition and gives . Adding on the right gives . Both return Unit.
Each removal requires a nonempty incoming sequence. getLeft() returns its first entry and leaves the remaining final sequence; getRight() returns its last entry and leaves the remaining initial sequence. These contracts remove exactly one occurrence, so duplicate values are permitted and do not collapse the sequence into a set.