Skip to content

Proposal for Abstract Classes and Methods #3578

Closed
@aozgaa

Description

Proposal for Keyword abstract

This is a proposal for a new keyword, abstract, to allow for incomplete/partially implemented classes.

Introduction

This proposal expands upon #6, #2946, #2947.

Consider the following situation. A user would like to create a base class that shouldn't be instantiated as a template for derived classes. S/he might write something like

class Animal {
    public age : number;
    public yearsLeft() { return 20 - this.age; }
    public makeSound() : string { return "???"; }
}

class Cow extends Animal {
    makeSound() { return "Moo"; }
}

class Cat extends Animal {
    makeSound() { return "Meow"; }
}

Today, the writer is forced to make a choice: either (i) Animal can be declared an interface, but then yearsLeft cannot have an implementation, or (ii) write the program as above, but then Animal can be instantiated and makeSound has a bogus implementation! Neither of these options is particularly attractive.

We propose abstract as a class declaration modifier to allow the programmer control over whether a class can be instantiated, and as a member function modifier to control whether said member function offers an implementation (and whether the enclosing class is abstract).

Details

The modifier abstract can prepend a class declaration or a member function declaration. Constructors cannot be declared abstract.

  • Objects whose type is typeof C where C is an abstract-declared class (hereafter abstract class) cannot be instantiated via calls to new.
  • A member function declared abstract does not have an implementation.
  • Abstract methods cannot be called within a class member function body via super.foo() where foo is an abstract method belonging to the parent class.
  • Abstract methods may be called within a class member function body via this.foo() where foo is an abstract method belonging to that class.
  • If a class has any abstract methods, then the class itself must be declared abstract.
  • Abstract methods are inherited.
  • Abstract methods can be overridden in the derived class, either by an abstract method (effectively a re-declaration) or a function declaration that offers an implementation.
  • A method cannot be simultaneously abstract and static.
  • A method cannot be simultaneously abstract and private.
  • If an abstract member declaration contains an explicit accessibility modifier, then the modifier must precede the abstract keyword.
  • Overloads on a member function must be either all abstract or all not abstract.
  • Overloads of abstract member functions must be declared adjacent to eachother.
  • Objects whose type is the type of an abstract class can only be assigned to other objects whose type is the type of an abstract class. For example,

The following code snippet summarizes valid and invalid usages of the abstract keyword

class A {
    // ...
}

abstract class B {
    foo(): number { return bar(); }
    abstract bar() : number;
}

new B; // error

import myB = B;
new myB; // error

var BB: typeof B = B;
var AA: typeof A = BB; // error, AA is not of abstract type.
new AA;

function constructB(Factory : typeof B) {
    new Factory; // error -- Factory is of type typeof C
}

var BB = B;
new BB; // error -- BB is of type typeof C

var x : any = C;
new x; // okay -- undefined behavior at runtime


class C extends B { } // error -- not declared abstract

abstract class D extends B { } // okay

class E extends B { // okay -- implements abstract method
    bar() { return 1; }

abstract class F extends B {
    abstract foo() : number;
    bar() { return 2; }
}

abstract class F {
    abstract qux(x : number) : string;
    abstract qux() : number;
    y : number;
    abstract quz(x : number, y : string) : boolean; // error -- declarations must be adjacent

    abstract nom() boolean;
    nom(x : number) boolean: // error -- use of modifier abstract must match on all overloads.
}

class G { // error -- not declared abstract
    abstract baz() : number;
}

Pros

  • Allows the programmer to write partial implementations of a class.
  • Provides a mechanism for the type system to warn about classes that shouldn't be instantiated.
  • abstract annotations clarify the role of base classes in various patterns.

Cons

  • Increases the complexity of the language.

To Be Discussed

  • Should abstract be allowed within class expressions?

Proposed Changes to Grammar

A.6 Classes

  ClassDeclaration:
   abstractopt class Identifier TypeParametersopt ClassHeritage { ClassBody }

  MemberFunctionDeclaration:
   MemberFunctionOverloadsopt MemberFunctionImplementation
   AbstractMemberFunctionOverloads

  AbstractMemberFunctionOverloads:
   AbstractMemberFunctionOverload
   AbstractMemberFunctionOverloads AbstractMemberFunctionOverload

  AbstractMemberFunctionOverload:
   AccessibilityModifieropt abstract PropertyName CallSignature ;

A.10 Ambients

  AmbientClassDeclaration:
   abstractopt class Identifier TypeParametersopt ClassHeritage { AmbientClassBody }

  AbstractOrStatic:
   abstract
   static

  AmbientPropertyMemberDeclaration:
   AccessibilityModifieropt AbstractOrStaticopt PropertyName CallSignature ;

EDIT: updated to clarify the assignability of objects of "abstract type".

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    CommittedThe team has roadmapped this issueFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions