The five printed lines, including the comma and space after every fragment, are:
f1 in C, 
f1 in C, f2 in B, 
f1 in C, f2 in A, f3 in B, 
f1 in A, f2 in A, f3 in ObjB, f4 in B, 
f1 in ObjC, f2 in A, f3 in B, f4 in ObjC, f5 in C, 
Scala dynamic dispatch uses the receiver's runtime software class, even though a has the static type A. Thus a.f1 uses C.f1, and a.f2 uses B.f2 whose unqualified f1 still dispatches on the new C receiver.
For a.f3, B.f3 explicitly selects super.f2, which is A.f2. Inside A.f2, the unqualified call to f1 still dispatches to C.f1; super does not replace the receiver. For a.f4, B.f3 in the body of class B means a call on the singleton object B, not on this. That object's f3 calls A.f2, which calls A.f1.
Finally a.f5 calls C.f4 on the singleton object C. That object extends class B, overrides f1 and f4, and inherits class B's f3. Its f4 calls this inherited f3; that selects A.f2, whose f1 dispatches to the object's own override. These distinctions follow member selection and super semantics.[ref]

Articles by others on the same topic (0)

There are currently no matching articles.