Feature request: traits #915
Replies: 2 comments
-
Traits are valuable because we want to define a shape to a type, so we can write parametric functions that take those shapes. So when we write: static bool IsEqual<A>(A x, A y) where A : IEquatable<A> We're stating we want the Code-generation doesn't allow types to be extended like this in a reasonable way. Ad-hoc polymorphism is possible, I document how to do it on the home-page, this is effectively the same as traits in Scala, or Type-classes in Haskell. The limitation then becomes the lack of higher-kinded types, which makes traits like It works well for lower-kinded types though. For example // Semigroup is the base of monoid
public interface Semigroup<A>
{
A Append(A x, A y);
}
// Monoid gains a unit element
public interface Monoid<A> : Semigroup<A>
{
A Empty();
} With the 'traits' defined, we can then create instances of those traits (which must be structs): public struct MString : Monoid<string>
{
public string Empty() => "";
public string Append(string x, string y) => x + y;
}
public struct MSeq<A> : Monoid<Seq<A>>
{
public string Empty() => Seq<A>();
public string Append(Seq<A> x, Seq<A> y) => x + y;
}
public struct MProduct : Monoid<int>
{
public string Empty() => 1;
public string Append(int x, int y) => x * y;
}
public struct MSum : Monoid<int>
{
public string Empty() => 0;
public string Append(int x, int y) => x + y;
} We can then define a polymorphic function that takes a trait like so: static A Concat<MonoidA, A>(params A[] xs)
where MonoidA : struct, Monoid<A> =>
Seq(xs).Fold(default(MonoidA).Empty(), (s, x) => default(MonoidA).Append(s, x)); That shows that This means we can then build ad-hoc functionality: var r1 = Concat<MProduct, int>(1, 2, 3, 4, 5); // 120
var r2 = Concat<MSum, int>(1, 2, 3, 4, 5); // 15
var r3 = Concat<MString, string>("Hello", " ", "World"); // "Hello World"
var r4 = Concat<MSeq<int>, Seq<int>>(Seq(1, 2, 3), Seq(4, 5)); // [1, 2, 3, 4, 5] This I believe is the basis of what the I have been thinking about this technique more recently (especially as I don't expect something in C# for a long time); and I have been thinking about how awkward this technique is to use. You'd want to be really keen on writing something super-generic to put up with this (lots of generic arguments). I had considered something a little less onerous, which would use the type-resolution system that |
Beta Was this translation helpful? Give feedback.
-
Thank you for explanation. Documentation/help of this kind is a good thing, helps a lot. Probably I wasn't clear enough or just mis-use 'trait' here (or just think into the wrong direction). I'm looking for a way to build e.g. a Example:
Some helper interface (e.g. in LanguageExt) for this:
Then code gen would process each class implementing some This would e.g. be:
Already defined functions would be skipped (or get some other, internal name, so they could be called like base methods). The whole point or this is that I want to inherit the methods / properties of some base type (or interface) but don't want to use inheritance. If I supply my own logic for generating the instance ( Note: If you look at the example you see that I inherit from Two things I have a mixed feeling:
|
Beta Was this translation helpful? Give feedback.
-
Found this old blog post via StackOverflow:
https://codecrafter.blogspot.com/2011/05/nroles-experiment-with-roles-in-c.html
It's about "adding" features to classes without (mis)using inheritance but by using composition with delegation.
Sadly C# requires me to implement all member explicitely.
Could this be done (in a reasonal way) by LanguageExt? CodeGen using partial classes...
Seems that default interface methods don't solve (parts of) this issue in a practical way because I would have to cast the class to the feature (trait) I want to use.
I see a lot of possible use cases.
Beta Was this translation helpful? Give feedback.
All reactions