Proposal: Reduce boilerplate by allowing fields in interfaces aka "traits" #9812
Replies: 4 comments 17 replies
-
|
#8075. It's just composing, and will immediately meet the famous diamond inheritance issue. |
Beta Was this translation helpful? Give feedback.
-
|
Are you wanting to pass these instances of these contracts around, like interfaces? i.e. public void DoSomething(cEditorContext ctx)
{
ctx.markVirtualizationAsDirty = true;
}Because, if not, you can write a source generator that adds the default members to any class marked with an appropriate attribute. It can be written to not add a specific member if the user-code already defines one. |
Beta Was this translation helpful? Give feedback.
-
Isn't defining traits to be state-less at one side and requesting fields for them on the other side a contradiction in itself? Do I miss something? |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi I did rewrite this, and renamed contracts into traits since I think its the better naming.
The reason for a trait-like system is code organization, which is poorly reflected in object-oriented practices and often leads to bloated, cross-referencing code that is hard to maintain and has poor performance characteristics.
A trait-like system would work as a local slice or organizational pattern for related, optional systems.
Inheritance organizes code vertically through ancestry. Traits do the same horizontally, by sharing capabilities across unrelated types. Traits are the missing horizontal dimension needed for truly clean and compositional OOP.
Usually, when you want to have objects with certain shared behaviours, you have three options (excluding factory patterns and focusing on raw language features):
You can write software this way, but it often ends up becoming an entangled mess of indirections and deep layers of nested complexity.
Traits, as stateless, non-instantiable interface-like structures that let you define required fields, would solve this issue with object-oriented languages.
Positive effects on code design would be:
Like call me crazy, but traits would be a wonderful addition to C# solving a lot of problems that exist in large code bases.
Lifetime Managment:
Traits and their auto field definitions are part of the object that holds them, so default values, can be written like this:
Constructors:
Generics:
Reflection:
There are quite some other points like static fields, trait inheritance and if they can implement interfaces (prob yes to interface + statics). That are still missing, but they could be a powerful addition to C#. The examples here are just small code bases, the real value would come when you implement things that are larger. Like a TPopupWindowManager or anything like it.
One major issue is trait inheritance, since it would recreate problems that OOP recreates. The remaining question, that maybe even breaks this whole system is:
Is trait inheritance worth the complexity? Or should traits remain flat, composable units that avoid hierarchical thinking entirely?
This is a large question for such a proposal. If they stay flat, then we are potentially back to standalone instances. If they are hierarchical it opens another can of worms. This would need to be tested when writing code within such a system and if the complexity they would add to C# is worth their functionality. They may be better off to be a functional flat part of C#, offering component based functionality without inheritance. So instead of:
GameObject → Entity → Character → Player
you get:
Player : TMovable, TRenderable, TPhysical, TControllable
screams in java xD
And yes you are close to this point with interfaces, but traits would just offer an additional code organization pattern, they keep the rest as is. And just allow better code organization & separation of concerns.
The diamond inheritance problem is no problem, since a trait works like an interface and is stateless, double definitions merge. So having two traits that require the same fields, is the same as having two interfaces that offer the same method.
Ok back to coding, those interfaces aren't going to implement themselves... unfortunately^^
Beta Was this translation helpful? Give feedback.
All reactions