4

i added map(), reduce() and where(qlint : string) to a Spring4D fork of mine. While i was programming these functions, i found out that there is a differnce in the behaviour of the lists, when they are created in different ways.

If i create them with TList<TSomeClass>.create the objects in the enumerables are of the type TSomeClass.

If i create them with TCollections.CreateList<TSomeClass> the objects in the enumerables are of the type TObject.

So the question is:

Is there a downside by using TList<TSomeClass>.create ?
Or in other words: Why should i use TCollections.CreateList<TSomeClass> ?


btw: with TCollections.CreateList i got a TObjectList and not a TList. So it should be called TCollections.CreateObjectList... but that's another story.

Benedikt
  • 767
  • 6
  • 13
  • 1
    Doesn't ring true. `TCollections.CreateList` returns an `IList`. When you enumerate that the items are of type `TSomeClass`. In other words, I call into question all that you claim in the post. – David Heffernan Sep 14 '16 at 15:55
  • As for downside of using `TList` directly, I think that will become apparent if you ever take a reference to an interface that it implements. At that point the lifetime management will be taken over by the interface references and you might find it disappearing from beneath you. So, use `CreateList` and hold `IList` or `IEnumerable` rather than the implementing class. One of the principles of this library is that you don't need to know the details of the implementation. However, I know little of Spring4d so I could have got completely the wrong end of the stick here ...... – David Heffernan Sep 14 '16 at 16:06
  • It was badly explained. The differnce is only inside `TEnumerable`. I was programming some new intern functions to `TEnumerable`. In my new function the RTTI calls behaved differently, because i was using the generic type of the enumerater (i know that was wrong from the beginning. But it was easy to start with). For someone who is just using the class there is no differnece to see. – Benedikt Sep 15 '16 at 14:15
  • I was just curious why the difference is there and why he is doing the folding stuff. I just didn't know, and didn't understand, the concept of folding a class. Thanks to Stefan Glienke i now know why it is done.... now i have to do my homework and find out how it is done, and what that means for my programming life. – Benedikt Sep 15 '16 at 14:15
  • 1
    I was looking at an older version of the library without this folding stuff. None of it would be necessary if Emba would do their job properly and write a decent linker to strip duplicate code. – David Heffernan Sep 15 '16 at 14:22

1 Answers1

13

Depending on the compiler version many of the Spring.Collections.TCollections.Create methods are applying what the compiler is unable to: folding the implementation into only a very slim generic class. Some methods are doing that from XE on, some only since XE7 ( GetTypeKind intrinsic function makes it possible to do the type resolution at compile time - see the parameterless TCollections.CreateList<T> for example).

This greatly reduces the binary size if you are creating many different types of IList<T> (where T are classes or interfaces) because it folds them into TFolded(Object|Interface)List<T>. However via the interface you are accessing the items as what you specified them and also the ElementType property returns the correct type and not only TObject or IInterface. On Berlin it adds less than 1K for every different object list while it would add around 80K if the folding is not applied due to all the internal classes involved for the different operations you can call on an IList<T>.

As for TCollections.CreateList<T> returning an IList<T> that is backed by a TFoldedObjectList<T> when T is a class that is completely as designed. Since the OwnsObject was passed as False it has the exact same behavior as a TList<T>.

The Spring4D collections are interface based so it does not matter what class is behind an interface as long as it behaves accordingly to the contract of the interface.

Make sure that you only carry the lists around as IList<T> and not TList<T> - you can create them both ways (with the benefits I mentioned before when using the TCollections methods). In our own application some places are still using the constructor of the classes while many other places are using the static methods from Spring.Collections.TCollections.

BTW:

I saw the activity in your fork and imo there is no need to implement Map/Reduce because that is already there. Since the Spring4D collections are modelled after .NET they are called Select and Aggregate (see Spring.Collections.TEnumerable). They are not available on IEnumerable<T> directly though because interfaces must not have generic parameterized methods.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • Thanks for the hint on "select" and "aggregate". That delphi does not allow generic parameterized methodes in interfaces, did give me some headaches too. That's why i opened up four default maps() that i could use through IEnumerable. I think i have to do some more homework on how the delphi compiler works. – Benedikt Sep 15 '16 at 13:08
  • btw: sorry that i didn't saw that the list gets created with "OwnsObject = False". That was my fault. So all your naming is right :) – Benedikt Sep 15 '16 at 13:14