Hi,
The problem is that, we like OOP inheritance but when we extend classes we are
forced into a single hierarchy.
there is another way to extend classes without inheritance: type helpers
Traits are like reverse type helpers. With the type helper you first
declare the class and then the extending helper.
=== code begin ===
type
TTest = class(TObject)
public
procedure test(a: integer);
end;
TTrait = class helper for TTest
procedure test2;
end;
procedure TTest.test(a: integer);
begin
writeln(a);
end;
procedure TTrait.test2;
begin
test(10);
end;
//var x: ttest2;
//x.test2
=== code end ===
With traits you could first define the extension, and then the class:
=== code begin ===
type
TTrait = trait
procedure test2;
end;
TTest = class(TObject, TTrait)
public
procedure test(a: integer);
end;
procedure TTest.test(a: integer);
begin
writeln(a);
end;
procedure TTrait.test2;
begin
test(10); //here it needs to know the test function exist. Perhaps
declare it in the the trait, too?
end;
//var x: ttest2;
//x.test2
=== code end ===
But otherwise, it looks exactly the same
Perhaps the type helper code could be reused for traits
Cheers,
Benito
On 18.02.21 04:37, Ryan Joseph via fpc-pascal wrote:
On Feb 17, 2021, at 9:59 AM, Adriaan van Os via fpc-pascal
<fpc-pascal@lists.freepascal.org> wrote:
1. multiple inheritance is nice to have, but it has the big issue that the
inheritance tree becomes an inheritance graph and that makes overrules
ambiguent.
2. interfaces don't have this issue with multiple inheritance, because they
just declare, not implement
3. but that is also the weakness of interfaces, as we don't want to
reimplement the same code each time
4. so, we really want an multiple-inheritance graph at the declaration level
with clear tree-like unambigous inheritance paths at the implementation level
5. thus, the idea is to "push-in" implementation code into an interface that
integrates fully at the declaration level but is independent at the implementation level.
I would say that's right.
The problem is that, we like OOP inheritance but when we extend classes we are forced
into a single hierarchy. We could use existing delegation patterns and dot-notation like
obj.helper.DoSomething or by breaking out entirely and using plain functions but then we
lose some of what makes OOP nice, which is, simply saying
"something.DoFunction". It may be trivial in terms of typing but it's elegant
and in my opinion clean code which is not tedious to write makes happy and more
productive.
Here's a more practical example but there are other possibilities for
composition patterns (I'l think of examples later). I copied this from the RTL
and made some changes. Assume you have this hierarchy and you want to add some
methods/data to JPEG and GIF images but not TIFF and PNG (they have some
special compression needs or something like that). What we would do now is
probably just dump them into TCustomBitmap (and bloat TIFF/PNG) or make
another subclass just to store the extra methods (which is useless besides
being a method store for 2 specific other classes).
What I want with traits is that I can extend those 2 classes with specific
functionality, still retain the object-orientedness of the syntax and not get
trapped trying to inject stuff into a hierarchy where it doesn't really belong
anyways.
TTIFFBitmap TPNGBitmap TJPEGBitmap TGIFBitmap
|
TCustomBitmap
|
TRasterImage
|
TGraphic
|
TPersistent
|
TObject
Regards,
Ryan Joseph
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________
fpc-pascal maillist - fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal