-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggestion: abstract classes #6
Comments
👍 The example would be more awesome if you incorporate abstract class Base {
abstract getThing(): string;
getOtherThing() { return 'hello'; }
virtual getVirtualThing() { return 'hello virtual'; }
}
... |
@am11 given that methods in JS get called by traversing the prototype chain, all methods are already "virtual" in the traditional sense that C++, C#, Java, and similar languages define it. For instance: class E {
f () { alert("E"); }
}
class F extends E {
f () { alert("F"); }
}
var x: E = new F();
x.f(); will alert "F". Did you have something else in mind? |
@DanielRosenwasser, that is so true. Thanks! Actually, I was thinking about the conventional OO keywords I believe this way we can bring C#'s new modifier as well: abstract class A {
public void foo() { }
protected virtual void bar() { }
}
class A1 : A {
protected override void bar() { }
} there may exist A2, such that: class A2 : A {
public new void foo() { }
} to explicitly hide super's implementation (without |
Seems like the example above has enough information to discuss. Some open questions:
|
Since abstract class -- in principle -- serves a purpose of grouping commonalities together such that its objects alone don't make sense; I think we should rule no_abstract_method as a legit case and let the TypeScript linter take care of recommending best practices, code-styling et el.
Given an abstract class would be able to inherit another abstract class, implicit inference like this would be confusing? I guess (at least C#/Java) developers would expect compiler to throw error and editor to help them correct it, if the first non-abstract / concrete implementer is missing any expected |
Even before class BaseClass {
myFunction() { /* TO BE OVERRIDDEN */ }
}
class MyClass extends BaseClass {
myF // intellisense should have kicked in -- but it doesn't
} My only option is to open BaseClass.ts to check I'm spelling it correctly. |
I'd still prefer to see more descriptive keywords, as I mentioned on https://typescript.codeplex.com/discussions/449920
From these more descriptive keywords, it can be seen immediately that the |
We're trying to clear out our design backlog and I think this should come up soon once ES6 features are wrapped up. We discussed |
The standard design pattern in JS is to throw an exception in the abstract class:
The benefit TypeScript could provide is reducing boilerplate and a compile-time error. |
Discussed today in the design meeting. The open question here is how we prevent you from trying to instantiate an abstract class. Consider some code: abstract class Abs {
constructor() { /* some general init here */ }
}
var x = new Abs(); // Desired: error This case is easy -- when you invoke Next: var a = Abs;
var x = new a(); // Not a good thing to do This is less obvious. You probably want an error? But then consider this case: class B extends Abs { /* ... */ }
class C extends Abs { /* ... */ }
var t: typeof Abs;
if(/*... */) {
t = B;
} else {
t = C;
}
var j = new t(); // This is fine There's nothing distinguishing this case from the previous one (in terms of the type system), but the latter is perfectly valid code to write (and would probably even be common code to write in a factory method). We will probably have to not error on the |
What about an hidden field? Let's say we have a class
Because the class is I don't know if it's a proper solution, or even if it's possible, but the point is to check if the closest class is abstract or not, whatever if it extends and abstract class or not. |
I think, you don't have to go crazy with this. |
Abstract type shouldn't have visible constructor. i.e. If user wants constructible type he should explicitly allow it which is possible thanks to type unions:
|
I would have thought that a type being abstract would be a bit in the type system. That's how people code it up in other functional languages. Then the compiler maintains knowledge of which types are abstract and which are concrete. Make sense? |
I wouldn't mind if the I feel the common use case is to simply define abstract methods that are left for child classes to implement. |
I like two proposed solutions personally,
|
@Griffork, your first proposition wouldn't allow for @RyanCavanaugh, instances like your Also, are you definitely going with the |
I don't think any alternatives have even been mentioned. |
I think For alternatives in other scenarios that you may use To spell it out, I think |
@RamIdeas Good point, didn't think of that. Alternatives to mustoverride and mustinherit that are more descriptive of the current behaviour than the intended use case would include notcallable and notnewable. After all, you can't garentee how something is going to be used, but you can garentee it's state, and that's what the abstract and virtual keywords were designed to do. |
I would say prevent directly instantiating abstract classes at compile time. Otherwise let it be a run time error. It works the same way in other statically typed languages. // e.g. C#
object value = new Stream(); // compile time error
Type type = typeof(Stream);
value = Activator.CreateInstance(type); // this compiles fine but will fail at runtime What about something like this to prevent runtime instantiation? // TypeScript
abstract class GreeterBase {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
abstract greet(): void;
}
class Greeter extends GreeterBase {
constructor() {
super("World");
}
greet() {
alert("Hello, " + this.greeting);
}
} // JavaScript
var GreeterBase = (function () {
function GreeterBase(message) {
throw new Error("Cannot instantiate abstract class");
}
GreeterBase.prototype.__ctor = function (message) {
this.greeting = message;
}
return GreeterBase;
})();
var Greeter = (function (_super) {
__extends(Greeter, _super);
function Greeter() {
_super.prototype.__ctor.call(this, "World");
}
Greeter.prototype.greet = function () {
alert("Hello, " + this.greeting);
};
return Greeter;
})(GreeterBase); |
That sounds like the best solution. Sent from my iPhone
|
@enoshixi |
Just an idea of a more JScript oriented implementation of abstract methods, without abstract classes
and used as
If you wanted to prevent public construction of GreetBase then perhaps the constructor could be decorated with "protected" |
Going to delete a bunch of 👍 comments to make this thread shorter (upvote feature please GitHub!). List of fine people who have 👍'd: |
Accepting PRs. Design notes for potential implementors:
|
For the record, I'm currently (trying) to implement this. edit What is the best way for this? First some basic stuff and create a PR for review? Or implement it with full test-suite and stuff? Because when I'm moving in total wrong direction I might waste a lot of my time and maybe yours too. |
We are open to looking at incremental changes. Just make sure the first iteration is substantial enough to warrant feedback. I would recommend sharing your approach and design on this issue before jumping into implementation. this way we can help save you time early on. |
I think this should be reconsidered. Special-casing only a direct "new MyAbstractClass" (rather than removing abstract classes' Earlier, this code was given as an example in favor of abstract classes having a
But In fact, using
Because |
@jeffreymorlan there was a suggestion that users can program their abstract classes to error in the constructor if they wanted it to (it's above) like this: class classa {
constructor () {
if(Object.getPrototypeOf && (Object.getPrototypeOf(this) === classa.prototype) {
throw new error("classa is abstract and should not be directly instantiated");
}
}
} This specifically checks of classa is 'bottom' of the prototype chain. |
Merged into |
In case you are wondering, it all happened with #3579 (with no back reference to this original issue 😢) |
Yeah, thanks @aozgaa! Lately, I've been adding many, many Beta/Alpha 1.6 cannot come soon enough 😉 |
My apologies about not offering the back-reference. Thanks @jasonwilliams200OK for linking above! |
Support an
abstract
keyword for classes and their methodsExamples:
The text was updated successfully, but these errors were encountered: