Should certain abstract classes be instantiable?

Justin Johansson no at spam.com
Fri Oct 2 16:13:32 PDT 2009


Andrei Alexandrescu Wrote:

> Jarrett Billingsley wrote:
> > On Thu, Oct 1, 2009 at 4:30 PM, Andrei Alexandrescu
> > <SeeWebsiteForEmail at erdani.org> wrote:
> >> Consider:
> >>
> >> class A {
> >>    abstract void fun() {}
> >> }
> >>
> >> The class defines a function that is at the same time abstract (so it
> >> requires overriding in derivees) and has implementation.
> >>
> >> Currently the compiler disallows creation of objects of type A, although
> >> technically that is feasible given that A defines the abstract method.
> >>
> >> Should A be instantiable? What designs would that help or hinder?
> > 
> > Uh... why?

> Because I want to give a good argument one way or another in TDPL. FWIW, 
> "I can't imagine why you'd ever..." or "Never needed that" are not 
> strong enough arguments.

> Andrei

I had a brilliant maths teacher at high school.  Every now and then
someone would ask a question which everyone else though was silly.

Often he would jokingly reply, "Good question.  Next question." and then,
after a pause, explore the subtleties of the "silly" question to everyone's
total amazement.

There was one really, really smart guy who asked enough "silly" questions
and ended up getting his Ph.D. in Mathematics before the age of 20.


> "Because I want to give a good argument one way or another in TDPL."

Fair enough, Andrei.  I'm trying hard with the following use case
to demonstrate that instantiation of the abstract is possibly useful.

Hope this helps or leads to further insight.


class NonNegativeInteger
{
   static NonNegativeInteger infinity;

   static this() {
      infinity = new NonNegativeInteger();
   }

   /+abstract+/ long value() {
      // In Andrei's scenario, this method is marked abstract
      // so we don't really care what we return here;
      // For moment comment out abstract keyword so that the
      // initialization of the singleton instance of
      // NonNegativeInteger, infinity, gets past the current
      // compiler.
      // Other than the private singleton instantiation inside
      // the static this block, no external code is allowed to
      // call new NonNegativeInteger() because the class
      // is, for all intensive purposes, abstract (once the
      // abstract keyword is uncommented).

      assert(false);
      return infinity.value;
   }

   void print() {
      writefln( "Infinity");
   }
}


class FiniteNonNegativeInteger: NonNegativeInteger
{
   private long val;
   
   this( long value) {
      val = value;
   }
   
   long value() {
      return val;
   }

   NonNegativeInteger opDiv( NonNegativeInteger divisor) {
      return (divisor.value != 0) ?
            new FiniteNonNegativeInteger( value / divisor.value) :
            NonNegativeInteger.infinity;
   }

   void print() {
      writefln( "%d", val);
   }
}


void main() {

   auto hundred = new FiniteNonNegativeInteger( 100);
   auto two = new FiniteNonNegativeInteger( 2);
   auto zero = new FiniteNonNegativeInteger( 0);
   auto fifty = hundred / two;
   auto infinity = hundred / zero;

   hundred.print();
   two.print();
   fifty.print();
   infinity.print();
   
}

Outputs:
   
   100
   2
   50
   Infinity


Cheers

Justin Johansson.





More information about the Digitalmars-d mailing list