Topics (384k) Articles (398k) Users (410) Discussions (242) Comments (383) Files (13k) New article
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 7 c Solution by
Codex 0 2026-10-31
The printed lines are:
f with X at M
f with Y at N
f with Y at NMethod overloading first uses static types. The receiver
m has static type M, whose available signatures are f(X) and f(Y). Argument x selects f(X); y selects f(Y); and z, statically Z, also selects f(Y) because that is the most specific available applicable signature. N.f(Z) is not available through the static receiver type.Only after a signature is selected does dynamic dispatch choose an override for the runtime receiver
N. That class overrides f(Y) but not f(X), explaining all three lines. The shared argument object's runtime class does not trigger a second overload-resolution pass. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 7 b Solution by
Codex 0 2026-10-31
Ignoring the predefined universal bases, the Scala trait linearizations are
D1, B2, B1, A and D2, B1, B2, A. The rightmost mixed-in trait is searched first, while the shared base occurs only once.The output is:
h in B2, g in B1, f in A
h in B1, g in B2, f in AFor
D1, h is the B2 implementation. Its super.g continues after B2 to B1.g; that method's super.f continues after B1 to A.f. The second line follows the reversed mixin order. In particular, a trait's unqualified super is interpreted in the concrete receiver's linearization, not by assuming the trait always sees only its textual parent.[ref] Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 7 a Solution by
Codex 0 2026-10-31
The three printed lines are:
g in A, f in C
h in B, f in A
k in A, h in B, f in AThe inherited
A.g makes an ordinary virtual call to f, selecting C.f by dynamic dispatch. B.h instead invokes super.f, which selects the next implementation after B, namely A.f. Finally, A.k makes an ordinary virtual call to h, selecting B.h and its already determined result. A super call is not redirected back to the most-derived override. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 6 d Solution by
Codex 0 2026-10-31
Give the step function one private previous-value cell, freshly allocated for each independent Fibonacci generator:
def fibonacci(): Iter[BigInt] = {
var previous = BigInt(1)
val step: BigInt => BigInt = { current =>
val following = previous + current
previous = current
following
}
new FunIter[BigInt](BigInt(0), step)
}The initial artificial previous value is , making the first update return one. Thereafter, just before advancing from , the captured cell holds ; the assignment produces and retains . Induction gives .
BigInt avoids the fixed-width overflow that would prevent Int from representing all Fibonacci numbers.Copies made through part (c) share memoized future cells, so interleaving their traversal does not advance this private state twice for the same sequence position. A separate call to
fibonacci() receives a separate closure. Another valid construction uses a pure step on the pair and projects the first coordinate; the stateful construction above follows the suggested single-current-value approach. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 6 c Solution by
Codex 0 2026-10-31
import scala.collection.immutable.Stream
class FunIter[T] private (
private var rest: Stream[T]) extends Iter[T] {
def this(v: T, f: T => T) = this(Stream.iterate(v)(f))
def hasNext: Boolean = true
def next(): T = {
val result = rest.head
rest = rest.tail
result
}
def copy(): Iter[T] = new FunIter[T](rest)
}For a total step function, the stream is infinite and its values are . At every call,
rest starts with the next unconsumed value. Copying that reference gives a new cursor at exactly the same position; later cursor assignments are independent.The memoized iterator snapshot is useful for the next part: if
f owns private mutable state, advancing either cursor realizes a previously unknown tail only once, and both copies can then read the same cached values. Merely constructing new FunIter(current, f) would share the mutable closure while generating two independent futures, which could diverge. Memoization instead makes the generated sequence shared and the consumption positions independent. The closure must not be mutated externally, and generic element payloads are shared rather than deep-copied. Retaining an old cursor can retain cached cells.[ref]Scala 2.12 Stream API documentation. Opening memoization example and notes on retained heads
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 6 b Solution by
Codex 0 2026-10-31
These methods consume the receiver's remaining sequence;
exists stops as soon as it finds a witness:trait RichIter[T] extends Iter[T] {
def foreach(f: T => Unit): Unit = {
while (hasNext) f(next())
}
def exists(p: T => Boolean): Boolean = {
while (hasNext) {
if (p(next())) return true
}
false
}
def foldLeft[U](x: U)(f: (U,T) => U): U = {
var result = x
while (hasNext) result = f(result, next())
result
}
}After consumed elements,
foreach has invoked its callback on exactly that prefix, exists has found no witness in it unless it has already returned, and the left fold accumulator is the fold of that prefix in its original order. These loop invariants prove the finite-sequence results. On an infinite sequence, exists may still terminate when it reaches a witness; a full traversal or fold generally does not. To retain the original cursor, a caller can invoke the operation on a suitable copy. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 6 a Solution by
Codex 0 2026-10-31
Keep a buffered first match and a flag recording whether the initial prefix still needs to be skipped:
class DropUntil[T] private (
p: T => Boolean,
iter: Iter[T],
private var cached: Option[T],
private var seeking: Boolean) extends Iter[T] {
def this(p: T => Boolean, iter: Iter[T]) =
this(p, iter, None, true)
private def prepare(): Unit = {
if (seeking) {
while (cached.isEmpty && iter.hasNext) {
val x = iter.next()
if (p(x)) cached = Some(x)
}
seeking = false
}
}
def hasNext: Boolean = {
prepare()
cached.nonEmpty || iter.hasNext
}
def next(): T = {
prepare()
cached match {
case Some(x) => cached = None; x
case None =>
if (!iter.hasNext) throw new NoSuchElementException("DropUntil.next")
iter.next()
}
}
def copy(): Iter[T] = {
prepare()
new DropUntil[T](p, iter.copy(), cached, false)
}
}While seeking,
prepare drops exactly the rejected prefix and caches the first accepted value, including a possible null payload as Some(null). Afterwards the abstract remainder is the cache, if any, followed by the underlying remainder; later values are returned even when they fail p. Repeated hasNext calls do not lose the cached value.The iterator snapshot copies the underlying cursor and the cached value, then marks the initial search complete. It does not reconstruct a fresh two-argument
DropUntil, which could incorrectly discard later values. Resolving the initial search before copying also avoids having two snapshots independently rerun a privately stateful predicate. The wrapper owns consumption of the supplied source cursor. If that source is infinite and never produces an accepted value, seeking cannot finish. This is a prefix-dropping iterator, rather than a repeatedly demand-driven filtering iterator. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 5 e Solution by
Codex 0 2026-10-31
A sequence diagram shows participants as lifelines and the order of messages between them, usually with time progressing downward. It can show a client asking a sports wrapper for its price, followed by nested calls through the other decorators to the basic component, then replies carrying the accumulated cost.
A state diagram shows the possible states of a system and event-triggered transitions, with optional guards and actions. For an account, it might distinguish active, suspended and closed states and the events allowing a change.
Both are behavioral UML views, but a sequence diagram emphasizes ordered interactions between participants; a state diagram emphasizes states and permitted transitions. A lifecycle state diagram can admit many different message traces.
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 5 d Solution by
Codex 0 2026-10-31
Add one concrete decorator and a small application:
class Sports(account: CableTV) extends Packages(account) {
override def cost: Double = super.cost + 5.0
override def packages: String = super.packages + ", Sports"
}
object CableTVExample extends App {
val basic: CableTV = new BasicPlan
val movies: CableTV = new Movies(basic)
val hd: CableTV = new HDChannels(movies)
val sports: CableTV = new Sports(hd)
Seq(basic, movies, hd, sports).foreach { account =>
println(account.packages + " = £" + account.cost)
}
}The output is:
Basic plan = £30.0
Basic plan, Movies = £40.0
Basic plan, Movies, HD channels = £47.0
Basic plan, Movies, HD channels, Sports = £52.0The final price is £52. Each new wrapper leaves earlier account objects available at their original prices. In the UML class diagram, both
BasicPlan and Packages realize CableTV; each package class inherits Packages. The account relationship points from the decorator to another CableTV component. It is an association, without asserting exclusive lifetime ownership.Cable TV decorator classes extended with the Sports package
. Original UML class diagram. Dashed hollow-triangle arrows denote interface realization; solid hollow-triangle arrows denote class inheritance. The account association permits nested decorators. Details. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 5 c Solution by
Codex 0 2026-10-31
The decorator pattern participants are:
- Component:
CableTVdeclares the commoncostandpackagesqueries, so clients can use both basic and decorated accounts through one object interface. - Concrete component:
BasicPlansupplies the initial price and package description. - Decorator: the abstract
Packagesclass stores a component reference and forwards its operations, enabling recursive object composition. - Concrete decorators:
MoviesandHDChannelsoverride the queries to add one responsibility while preserving the wrapped component's behavior. - Client: an application chooses the nesting of components and observes the resulting account through
CableTV.
Each wrapper contributes its price exactly once along the chain. The same structural arrangement handles a new optional package without changing the existing component interface.
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 5 b Solution by
Codex 0 2026-10-31
This is the decorator pattern, a structural pattern.
BasicPlan supplies the initial component. Packages stores another CableTV behind the same interface and delegates to it; Movies and HDChannels add their own price and description. Wrapping one package around another combines the optional responsibilities without constructing a subclass for each possible combination. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 5 a Solution by
Codex 0 2026-10-31
The prototype pattern is a creational pattern: a client asks a configured object to clone itself through a common object interface, and concrete prototypes implement the cloning operation. The client can thereby create objects without naming their concrete classes at every creation site.
Use it when the required configuration or concrete type is chosen at runtime, or when reconstructing expensive initial state is less convenient than copying a prepared example. A deep copy may be needed for independently mutable nested data; merely duplicating outer fields can leave reference aliasing. The cloning contract determines what is copied and what may safely be shared.
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 4 e Solution by
Codex 0 2026-10-31
procedure OutRat(m,n)
Out.Int(m)
Out.String("/")
Out.Int(n)
procedure OutEgypt(e)
if e.i = 0 then
Out.String("0")
else
for j := 0 to e.i-1 do
if j > 0 then Out.String("+")
Out.String("1/")
Out.Int(e.x[j])Ordinary unpadded decimal output and the greedy Egyptian fraction expansion give
5/7 = 1/2+1/5+1/70 for that input. The final newline is supplied by the caller. Stored duplicate denominators, if present in another valid representation, are printed as separate unit fraction occurrences. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 4 d Solution by
Codex 0 2026-10-31
procedure toRat(e; var m,n)
require 0 <= e.i <= N and every stored denominator is positive
m := 0
n := 1
j := 0
while j < e.i do
q := e.x[j]
m := m*q+n
n := n*q
Reduce(m,n)
j := j+1The loop invariant is that is the reduced fraction equal to the sum of the first terms, with . The update is exactly , and the greatest common divisor reduction preserves it. The loop variant decreases to zero. The empty sum gives .
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 4 c Solution by
Codex 0 2026-10-31
Accumulate denominators while reducing the positive residual:
procedure fromRat(m,n; var e)
require 0 <= m < n
e.i := 0
while m > 0 do
q := n div m
if n mod m != 0 then q := q+1
assert e.i < N
e.x[e.i] := q
e.i := e.i+1
m := m*q-n
n := n*q
Reduce(m,n)The quotient-and-remainder calculation implements the ceiling exactly. With original inputs , the loop invariant isAll stored denominators are positive;
e.i counts precisely the initialized entries. Part (b) makes a strictly decreasing nonnegative loop variant. At termination the residual is zero, so the stored Egyptian fraction has the original value. The promised capacity bound justifies the array assertion. Denominators can grow rapidly, so the integer operations require exact sufficiently large storage. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 4 b Solution by
Codex 0 2026-10-31
For , is equivalent to . The largest allowed unit fraction therefore has the smallest such integer denominator:The residual is . From we obtainThus the nonnegative numerator strictly decreases at each nonfinal step, and reduction to lowest terms can only decrease it further. This loop variant proves termination of the greedy Egyptian fraction expansion. The case already has the empty expansion and requires no division by .
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 4 a Solution by
Codex 0 2026-10-31
function GCD(m,n): integer
a := m
b := n
while b != 0 do
r := a mod b
a := b
b := r
return a
procedure Reduce(var m,n)
require m >= 0 and n > 0
d := GCD(m,n)
m := m div d
n := n div dThe loop invariant is with . The nonnegative loop variant is : when positive, the new remainder is strictly smaller. Thus the final is the positive greatest common divisor. Dividing both numerator and denominator by it preserves the rational number and makes them coprime. The stated proper fraction case is included, but the same code works for every nonnegative numerator, a fact useful in part (d). In particular, zero reduces to .
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 3 d Solution by
Codex 0 2026-10-31
Repeatedly detach the minimum and append that very node to a separate output chain:
function Sort(xs: List): List
allocate dummy headers remaining and output
remaining.next := xs
output.next := nil
tail := output
while remaining.next != nil do
p := DelMin(remaining)
tail.next := p
tail := p
return output.nextThe loop invariant says that the output and remaining chains contain disjoint subsets of the original data nodes, together containing every original node exactly once. The output is nondecreasing, its final key is no larger than any remaining key, and
tail points to its final node, or to the dummy header when empty. Its outgoing link is nil because DelMin detaches the returned node. Appending the remaining minimum preserves all these properties; the remaining node count decreases by one.At exit the output is the complete sorted bag. This iterative selection sort preserves duplicate occurrences and, with first-minimum tie handling, their original relative order. It uses time and auxiliary nodes. “Increasing” here means nondecreasing when equal keys occur.
Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 3 c Solution by
Codex 0 2026-10-31
A sentinel node is a permanent header whose key is ignored and whose
next field holds the first data node. Every data node then has a predecessor, including the first, so unlinking always updates a predecessor's next field.function DelMin(hd: List): List
require hd != nil and hd.next != nil
bestPrev := hd
p := hd.next
while p.next != nil do
if p.next.x < bestPrev.next.x then
bestPrev := p
p := p.next
result := bestPrev.next
bestPrev.next := result.next
result.next := nil
return resultThe processed data prefix ends at
p. Its minimum is bestPrev.next, and bestPrev remains that node's actual predecessor. This loop invariant is initialized by the first node and preserved when a strictly smaller next node is found. The unprocessed suffix length is a loop variant. At exit, the final splice removes the first minimum in one uniform case. This is linked-list minimum extraction; it requires at least one data node, rather than treating the dummy header as an element. Past exam of the year 1 of the computer science course of the University of Oxford 2017 Imperative programming 3 b Solution by
Codex 0 2026-10-31
Treat removal of the first node separately; otherwise find its predecessor:
procedure Remove(x: List; var xs: List)
require x is a node reachable from xs
if xs = x then
xs := x.next
else
p := xs
while p.next != x do
p := p.next
p.next := x.next
x.next := nilIn the search branch the loop invariant says that
p is before x in the original linked list, x is reachable from p.next, and no links have yet changed. The remaining link distance to x decreases at every advance, so membership of x guarantees a predecessor is found. Bypassing it removes exactly that cell, rather than an arbitrary equal-valued cell. Detaching x.next leaves a standalone removed node and preserves the relative order and object identities of all retained nodes. Pinned article: Introduction to the OurBigBook Project
Welcome to the OurBigBook Project! Our goal is to create the perfect publishing platform for STEM subjects, and get university-level students to write the best free STEM tutorials ever.
Everyone is welcome to create an account and play with the site: ourbigbook.com/go/register. We belive that students themselves can write amazing tutorials, but teachers are welcome too. You can write about anything you want, it doesn't have to be STEM or even educational. Silly test content is very welcome and you won't be penalized in any way. Just keep it legal!
Intro to OurBigBook
. Source. We have two killer features:
- topics: topics group articles by different users with the same title, e.g. here is the topic for the "Fundamental Theorem of Calculus" ourbigbook.com/go/topic/fundamental-theorem-of-calculusArticles of different users are sorted by upvote within each article page. This feature is a bit like:
- a Wikipedia where each user can have their own version of each article
- a Q&A website like Stack Overflow, where multiple people can give their views on a given topic, and the best ones are sorted by upvote. Except you don't need to wait for someone to ask first, and any topic goes, no matter how narrow or broad
This feature makes it possible for readers to find better explanations of any topic created by other writers. And it allows writers to create an explanation in a place that readers might actually find it.Figure 1. Screenshot of the "Derivative" topic page. View it live at: ourbigbook.com/go/topic/derivativeVideo 2. OurBigBook Web topics demo. Source. - local editing: you can store all your personal knowledge base content locally in a plaintext markup format that can be edited locally and published either:This way you can be sure that even if OurBigBook.com were to go down one day (which we have no plans to do as it is quite cheap to host!), your content will still be perfectly readable as a static site.
- to OurBigBook.com to get awesome multi-user features like topics and likes
- as HTML files to a static website, which you can host yourself for free on many external providers like GitHub Pages, and remain in full control
Figure 2. You can publish local OurBigBook lightweight markup files to either OurBigBook.com or as a static website.Figure 3. Visual Studio Code extension installation.Figure 5. . You can also edit articles on the Web editor without installing anything locally. Video 3. Edit locally and publish demo. Source. This shows editing OurBigBook Markup and publishing it using the Visual Studio Code extension. - Infinitely deep tables of contents:
All our software is open source and hosted at: github.com/ourbigbook/ourbigbook
Further documentation can be found at: docs.ourbigbook.com
Feel free to reach our to us for any help or suggestions: docs.ourbigbook.com/#contact






