-
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
Feature Request / Proposal: Traits #311
Comments
I think Mixins are relatively similar to traits, however, there are a few disadvantages (at least as it's described in the handbook):
Are the points 1 and 2 by design or are these feature yet to be implemented? |
Mixins is an ugly way that feels like we are using ecmascript 3. Traits would allow us to use a more object oriented clean syntax. |
This would certainly be awesome. I don't care how it's done, but this would be great--I use TS mainly in games and engines, and the ability to "mixin" methods from a trait would be great for actors/objects in games (for example, an object importing an EventDispatcher but inheriting from a base class).
I don't know how this will work with TS to allow using traits like interfaces (maybe simply traits can implement interfaces).
|
Traits as part of Typescript and its type system would be really helpful to use the DCI programming paradigm with (http://en.wikipedia.org/wiki/Data,_context_and_interaction). I would prefer a trait solution, where the trait is an interface with a default implementation. Such an interface alone would not generate any JS code on compilation.
Here is an example:
The "with" syntax is borrowed from Scala. Of course some other syntax could be used for mixing trait interfaces into a new instance, e.g.: I'm curious if this suggestion is compatible with the current Typescript type system. Any thoughts? |
Also, without multiple inheritance or traits, not possible to use TypeScript with Dojo Toolkit. The whole library is built on mixins system. Of course, we can use default "dojo/_base/declare", but this way negates the benefits from classes and interfaces in TypeScript. |
TypeScript team, are you guys open to receiving possible implementations of this feature? |
We'd be open to implementations in the future but it's important that we first nail down a proposal we can all agree on. It'd be getting ahead of ourselves to start reviewing an implementation before we nail down what is and isn't the intended behavior here. |
No problem. SitePen is currently working on defining some package specifications for Dojo and this is one of the areas that we are looking to improve, so once we get a bit further along and actually begin the work of defining technical proposals those will be brought here. A prototype implementation would be useful to inform that decision-making and may form a suitable foundation for a final implementation, but these are early days, we have no code yet. I just didn’t want to have anyone on this side start going down the road and then find out that there is no chance to accept this, or that after talking to @mhegazy about C3 linearization that you guys wanted to move in that direction instead. |
@jbondc Great! Looking over what you are proposing so far I would probably start by just focusing on the compiler side of things and not even thinking about any runtime enhancements in order to keep the initial feature very clear and focused (like the OP). I understand not wanting to introduce new reserved words that weren’t future reserved words in the EcmaScript spec but I/others will have additional feedback over the coming months on this. |
@jbondc, there is a similar proposal on the old codeplex site. What do you think about it? |
Just a brief update for everyone watching: I should have a complete(ish) proposal to share in the next couple of days at the latest. Sorry for the delay. |
Our proposal is now available at https://docs.google.com/a/sitepen.com/document/d/112Xw-t8eh-eFIdKhn7LeDbGhO86XwlKv-Fwc6j9U-Oc/edit for discussion. (Please let me know if you prefer this to be in another format/location.) This proposal focuses purely on enhancing the compiler and doesn’t include any runtime enhancements. Looking forward to your feedback and working with the rest of the team and community on refining these proposals into something that will be accepted into TypeScript. |
@csnover +1... but ... what about use only 'trait' instead of 'traitclass'? |
The use of an adjective was taken from the ES strawman, I have no particular affinity for that grammar. This really is a first draft to get feedback so if people think the adjective is wrong then I’ll update the proposal until mostly everyone is happy :) (I personally prefer multiple inheritance with C3 over traits since it covers more common use cases and is usually more intuitive for people that already know how single-inheritance works.) |
TypeScript team, do you have any feedback or can you let me know when you might have time to review this proposal? Is there information that is unclear that needs to be clarified before additional feedback can be solicited? |
I think the proposal is very clear. We're really busy wrapping up ES6 stuff at the moment so I can't give any hint of a timeline at this point. |
This might qualify as a separated feature, but I am wondering can a runtime-only version of traits be implemented so that native objects can be augmented in a more OO fashion. For example, say I define a "runtime trait" like
and then use it like Emit for the trait could be the same as the current compile-time version (i.e. as prototype properties in a Function). For the call site, In the type system, such trait can be treated like an interface. (With the same There can even be some Scala-inspired magic like implicit conversion (probably module-based to maintain sanity). |
Thanks everyone for the feedback and sorry for the delay. It would be nice to have a generic mechanism for combining types (like a
Agree on the constructors in traits, that was a mistake, can you put a comment on the proposal so I can remember to fix it there?
OK, no worries, I will try to clarify in the proposal. To give a little more background here, one reason to prefer C3 over traits is to avoid having to do a lot of (keyboard) typing especially when you are composing things together. It also lets the consumer of a library avoid understanding the right method ordering for every conflict method in order for it to work. So, as a concrete example, dgrid, a responsive data grid widget, allows users to enhance its functionality by composing together classes adding in mixins/extensions. Users start with a base Grid, add keyboard navigation by mixing in Keyboard, and add column resizing by mixing in ColumnResizer, etc. Even though some of these mixins implement the same methods, everything almost always Just Works transparently and the user doesn’t have to think about sorting out how the super-calls should be ordered. So they can write: class MyGrid extends Grid, Keyboard, ColumnResizer {} and they are finished and everything just works. In contrast using traits there would be numerous method conflicts, class MyGrid extends Grid {
use Keyboard {
destroy as destroyKeyboard,
postCreate as pcKeyboard,
// ... more here ...
};
use ColumnResizer {
destroy as destroyColumnResizer,
// ... more here ...
};
destroy() {
super.destroy();
this.destroyKeyboard();
this.destroyColumnResizer();
}
postCreate() {
return this.pcKeyboard(super.postCreate());
}
} And then if you ever change the way your grid is constructed you’d have to go through and find and fix all these methods explicitly too. Lots of work compared to letting C3 take care of it for you! (Replace the method renaming with symbols to the traits and it’s the same problem.)
From what I see you are introducing a conflict since you have traits A and B used by class C and trait A also extends trait B, how would this be resolved? I don’t see any conflict resolution in this feedback gist. C3 automatically fixes this ambiguity by reordering dependencies of all inherited classes. |
Also, sorry, somehow I neglected to link to wikipedia on C3 linearization for more background on how the algorithm works (it’s pretty straightforward if you can get past the pseudo-code, which makes it look more confusing than it is!), I added the link in the proposal. |
To be able to do this, programmer must know about all methods in all imported mixins and which of them are in conflict. Why he should if it is possible resolve this automatically like |
There's a lot of overlap here with mix-ins; it would be bad (or at least treacherous) to do both. With mix-ins being a potential part of ES7/ES8+, we want to take the runtime side of this very conservatively and get TC39 to agree on a proposal in this area first. Features specific to the type system to support these patterns are still on the table, but we'll track those in other issues. |
Is there an update on how/if mixins will become a first class capability of typescript rather than a bit of a hack with separated registration as it currently stands? |
I am sure I will be corrected if I am wrong, but the TypeScript team have made it clear that because this is a domain that TC39 has indicated they will address, the team feel that this is something it doesn't feel it can introduce as it would likely cause incompatibilities with ES in the future. The implications are, those of us who are passionate about it should be championing it within TC39. The concepts of mixins/traits were part of the originally Harmony proposals, but didn't make it into the spec. Also, as far as I am aware, there isn't any active advocacy on this specific area in TC39 at the moment. Once there is a proposal sufficiently through the process in TC39, then I believe the TypeScript team would be more than glad to implement it. |
@kitsonk thanks for the update, I guess we just have to hope for TC39, I'll see if I can find any discussion on the matter. I feel at this point that traits are the only major capability missing - I'm currently managing a site with ~50k sloc TS, and the mixin registrations are somewhat unwieldy. |
+1 for this feature |
What's the status on this feature? |
See https://blogs.msdn.microsoft.com/typescript/2017/02/02/announcing-typescript-2-2-rc/ ... basically they're not adding new language grammar, but by making some changes to the way Classes work, it's possible/easier to achieve now. |
One powerful pattern that is possible with traits is this (similar to what @jbman mentioned): trait AccountService {
debit: (account: Account, amount: number) => Account;
credit: (account: Account, amount: number) => Account;
transfer(from: Account, to: Account, amount: number): [Account, Account, number] {
return [this.debit(from, amount), this.credit(to, amount), amount]
}
} This is not something that TC39 can help us with as in this particular form it's only relevant to statically typed languages. It can be done with |
+1 |
You can have a look at a simple library i wrote at TypeScript Mix I think it fits nicely into how you would want to use traits/mixins |
ORIGINALLY PROPOSED IN http://typescript.codeplex.com/workitem/838
Traits, as "compile-time" partial classes, would perfectly fit with TS ideology and resolve problems of multiple inheritance/mixins.
Traits in Scala: http://en.wikibooks.org/wiki/Scala/Traits
Traits in PHP: http://php.net/trait
I propose minimal traits similar to PHP implementation.
The code above could be compiled to JS below (can be optimized, just showing the main idea):
Unresolved name conflicts should raise a compile time error.
I think it would be a great advance for the language. But the proposal has more than one year made (in codeplex) and has not yet been implemented.
The text was updated successfully, but these errors were encountered: