teaching machines

CS 330 Lecture 40 – Multiple Inheritance

May 11, 2016 by . Filed under cs330, lectures, specifications.

Agenda

TODO

Note

We start today with this task:

Design a reusable piece of Java code that allows a class to “listen” for just drag events. When such an event occurs, the class wants to be alerted through its onDrag(int fromX, int fromY, int startX, int startY) method.

How would you write this code?

Most of the listeners we use in Java are interfaces. They only announce methods that must be appear in their implementors. They contain no state. For the task above, we must have some state to remember the initial mouse position. We must have some implementation to call onDrag. Therefore, we cannot use an interface. We use an abstract class instead.

The cost of this is that we can’t extend our listener if we are extending another class. Java only allows single inheritance. We can workaround this with a local subclass. But one must wonder, what’s the big deal with multiple inheritance? Why does it not appear in many languages? Since some languages do support it, the answer can’t be that we don’t know how to support it. Instead, there are a few reasons that language designers choose not to implement it:

  1. It introduces ambiguity. Suppose two superclasses both implement method foo. When someone says sub.foo(), whose foo gets called? Likewise, suppose two superclasses both have an instance variable named x. When you access x in the subclass, whose x are you accessing? C++ overcomes this issue by requiring you to fully qualify references to ambiguous superclass identifiers.
  2. It complicates object layout in compiled programs. We saw last time that objects are a linear stack of their supertypes in memory. Subclasses pile their instance variables below the superclasses’. Instance variables are really just offsets from the beginning of an object’s memory footprint. When multiple inheritance comes in, the linearity of an object gets thrown out of whack.
  3. It introduces the dreaded diamond. Suppose two superclasses have a common superclass. When a subclass is constructed, does it get two separate grandparent foundations? Or just one? If just one, which of the two parent classes constructs it? C++ avoids this dreaded diamond through virtual inheritance, which basically shuts off all automatic superclass construction. The subclass must actively invoke the superclass constructors.

Code

cole.rb

/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
	from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
	from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
	from ./coderay:24:in `
'

DraggedListener.java

/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
	from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
	from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
	from ./coderay:24:in `
'

DrawFrame.java

/usr/lib/ruby/2.7.0/rubygems/dependency.rb:311:in `to_specs': Could not find 'coderay' (>= 0) among 56 total gem(s) (Gem::MissingSpecError)
Checked in 'GEM_PATH=/.gem/ruby/2.7.0:/var/lib/gems/2.7.0:/usr/lib/ruby/gems/2.7.0:/usr/share/rubygems-integration/2.7.0:/usr/share/rubygems-integration/all:/usr/lib/x86_64-linux-gnu/rubygems-integration/2.7.0:/home/johnch/.gems', execute `gem env` for more information
	from /usr/lib/ruby/2.7.0/rubygems/dependency.rb:323:in `to_spec'
	from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_gem.rb:62:in `gem'
	from ./coderay:24:in `
'