Mike Torrettinni 198 Posted June 17, 2020 I'm not sure the verbiage of title is correct, but here is the question: when I have TItem and TItems defined as: type TItem = record ... end; TItems: TArray<TItem>; Is there any obvious disadvantage of using TItems instead of using everywhere TArray<TItem> for variables, function results, parameters... ? I don't know how to phrase the question to ask google about this, in case this is widely discussed topic already. Share this post Link to post
Stefan Glienke 2009 Posted June 17, 2020 (edited) I think you meant to write: TItems = TArray<TItem>; Apart from not having to type the angle brackets anymore this is exactly the same type as TItems is just an alias for TArray<TItem> Edited June 17, 2020 by Stefan Glienke 1 1 Share this post Link to post
Bill Meyer 337 Posted June 17, 2020 32 minutes ago, Stefan Glienke said: I think you meant to write: TItems = TArray<TItem>; Apart from not having to type the angle brackets anymore this is exactly the same type as TItems is just an alias for TArray<TItem> Does using a defined type play any part in reducing the bloat of generics? Share this post Link to post
Mike Torrettinni 198 Posted June 17, 2020 39 minutes ago, Stefan Glienke said: I think you meant to write: TItems = TArray<TItem>; Apart from not having to type the angle brackets anymore this is exactly the same type as TItems is just an alias for TArray<TItem> Great, thanks for confirming. I knew such alias can be defined, but never really thought of defining and using it for my own arrays. Now I will! 🙂 Thanks, when I search for alias I get some results. Share this post Link to post
Mahdi Safsafi 225 Posted June 17, 2020 Yes, there is a disadvantage of using TArray<TItem> instead of TItems. In the same unit where class is declared, whenever compiler found explicit generic type(TArray<TItem>), compiler must do extra work : matching arguments, checking for constraints, ... In a large unit that uses generics massively, this may add a little overhead. TItems on the other side, works as a cache (compiler does not need to check constraints for example). Using TArray<TItem> from another unit adds a noticeable overhead as the compiler must generate the type in-situ for that unit. In fact do the following test yourself: unit Unit1; interface uses System.SysUtils, System.Generics.Collections, System.Classes; type TObject<T> = class a: T; b: T; procedure foo(a, b: T); end; TListOfInteger = TList<TObject<Integer>>; implementation { TObject<T> } procedure TObject<T>.foo(a, b: T); begin end; end. // --------------------------------------- unit Unit2; interface uses System.SysUtils, System.Generics.Collections, System.Classes, Unit1; type TListOfInteger2 = TList<TObject<Integer>>; implementation end. //----------------------------------------- unit Unit3; interface uses System.SysUtils, System.Generics.Collections, System.Classes, Unit1; type TListOfInteger3 = TListOfInteger; // alias implementation end. Now, check the size of Unit1.dcu, Unit2.dcu, Unit3.dcu. Final thing, TItems is more friendly for typing and reading ! 1 Share this post Link to post
Mike Torrettinni 198 Posted June 17, 2020 13 minutes ago, Mahdi Safsafi said: Now, check the size of Unit1.dcu, Unit2.dcu, Unit3.dcu. Final thing, TItems is more friendly for typing and reading ! Thanks for simple example, I see the difference. I use TArray<> a lot, will see if I can get used to defining these aliases. Share this post Link to post
David Heffernan 2347 Posted June 17, 2020 You are just polluting the namespace for no benefit. Use TArray<T>. 2 Share this post Link to post
Mike Torrettinni 198 Posted June 17, 2020 (edited) 12 minutes ago, David Heffernan said: You are just polluting the namespace for no benefit. Use TArray<T>. Isn't TArray<T> only for generic usage? I use it when I define generic method, and is used like TArray,Method<T>... Can it be used for specific usage, like: type TItem = record ID: integer; Text: string; ChildCount: integer; end; fData = TArry<TItem>; function GetText(aIdx: integer): string; begin Result := fData[aIdx].Text; end; Not sure how TArray<T> could be used in this example? Edited June 17, 2020 by Mike Torrettinni Share this post Link to post
Attila Kovacs 629 Posted June 17, 2020 TArray<TItem> is TArray<T>, TArray is a class. Share this post Link to post
David Heffernan 2347 Posted June 17, 2020 29 minutes ago, Mike Torrettinni said: Isn't TArray<T> only for generic usage? I use it when I define generic method, and is used like TArray,Method<T>. Those are two completely different things. One is a generic dynamic array type, the other is a generic method. Share this post Link to post
Uwe Raabe 2060 Posted June 18, 2020 8 hours ago, David Heffernan said: You are just polluting the namespace for no benefit. Use TArray<T>. As a benefit I see better readability and flexibility. In case we decide to change TArray<T> to something like a TList<T> later, we only have to change that in one place. (Of course the code itself might have to change, too. But that has to be done anyway.) I often start with an alias like TItems = TList<T> and later extend that to TItems = class(TList<T>) with some additional or overridden functionality. Sometimes it is just to hide the necessary constructor parameters inside a simple TItems.Create. If the implementation is indeed relevant for understanding the code, I use type names like TItemArray and TItemList, even if those are also just aliases to TArray<TItem> and TList<TItem>. For me, these benefits are of much more value than keeping the namespace small. The latter may result in shorter compile times, which are already pretty short. Runtime performance and code maintainability gain near to nothing from it. 4 Share this post Link to post
David Heffernan 2347 Posted June 18, 2020 I can't really see any benefit here. I mean you might think that TItemArray is somehow better than TArray<TItem> but they seem pretty interchangeable to me in terms of readability. And the reader has to trust that convention was followed with TItemArray. 1 Share this post Link to post
Stefan Glienke 2009 Posted June 18, 2020 (edited) 12 hours ago, Bill Meyer said: Does using a defined type play any part in reducing the bloat of generics? Not for TArray<T> but possibly for types with actual executable code - see my reply to Mahdi. 12 hours ago, Mahdi Safsafi said: Now, check the size of Unit1.dcu, Unit2.dcu, Unit3.dcu. Final thing, TItems is more friendly for typing and reading ! The question was about TArray<T> where it does not matter at all rather than a few unnoticable microseconds at compile time. You are right however when talking about types that have executable code (and possibly a significant amount of typeinfo) as the compiler always emits all code of a generic type into each and every dcu that is using it as in your example with Unit1 and Unit2. However it does not need to emit into Unit3.dcu because that one is just referencing the type that already fully resides in Unit2. Edited June 18, 2020 by Stefan Glienke Share this post Link to post
Mahdi Safsafi 225 Posted June 18, 2020 Quote The question was about TArray<T> where it does not matter at all rather than a few unnoticable microseconds at compile time. Just for clarification, I used two different word : little overhead & noticeable overhead to distinguish between two different usage of TArray<T>. Quote You are right however when talking about types that have executable code (and possibly a significant amount of typeinfo) as the compiler always emits all code of a generic type into each and every dcu that is using it as in your example with Unit1 and Unit2. However it does not need to emit into Unit3.dcu because that one is just referencing the type that already fully resides in Unit2. You definitely understood my example In fact, for Unit3, compiler only emitted interface for the alias-type without implementation (without machine code generation). For Unit1 and Unit2 it emitted the interface and the implementation (generated code). Share this post Link to post
Attila Kovacs 629 Posted June 18, 2020 I can remember the post on G+ by Stefan about the bloated .dcu's and the affected linking time, but this is the first time I see a "workaround". Share this post Link to post
Stefan Glienke 2009 Posted June 18, 2020 38 minutes ago, Mahdi Safsafi said: Just for clarification, I used two different word : little overhead & noticeable overhead to distinguish between two different usage of TArray<T>. I can't see a situation where TArray<T> can have noticable overhead as it does not have enough stuff to be generated - what you demonstrated was using a generic class that has executable code and RTTI. Share this post Link to post
Mahdi Safsafi 225 Posted June 18, 2020 @Stefan Glienke Aha I see ! I wasn't meaning "TArray<T>" in particular. My example even didn't used it . Share this post Link to post
Rollo62 538 Posted June 18, 2020 7 hours ago, David Heffernan said: I can't really see any benefit here. I mean you might think that TItemArray is somehow better than TArray<TItem> but they seem pretty interchangeable to me in terms of readability. And the reader has to trust that convention was followed with TItemArray. I can see also benefit in maintaining code. Imaging you change TItemArray = TArray<TItem>; to TItemArray = TArray<TItemEx>; In the TItemArray version you touch the code in one place only. In the TArray<TItemEx> version you touch the code in thousands of places maybe. 1 Share this post Link to post
David Heffernan 2347 Posted June 18, 2020 57 minutes ago, Rollo62 said: I can see also benefit in maintaining code. Imaging you change TItemArray = TArray<TItem>; to TItemArray = TArray<TItemEx>; In the TItemArray version you touch the code in one place only. In the TArray<TItemEx> version you touch the code in thousands of places maybe. Now you have the type named incorrectly in thousands of places. It should be called TItemExArray. Seems far worse to me. 2 Share this post Link to post
Mike Torrettinni 198 Posted June 18, 2020 4 hours ago, Rollo62 said: I can see also benefit in maintaining code. Imaging you change TItemArray = TArray<TItem>; to TItemArray = TArray<TItemEx>; In the TItemArray version you touch the code in one place only. In the TArray<TItemEx> version you touch the code in thousands of places maybe. This happens to me quite often, start with new feature and after a while I see the different naming would be more suitable. So, now changing an alias will be so much easier, because refactoring/rename of type doesn't always work across multiple units. Share this post Link to post
David Heffernan 2347 Posted June 18, 2020 8 minutes ago, Mike Torrettinni said: This happens to me quite often, start with new feature and after a while I see the different naming would be more suitable. So, now changing an alias will be so much easier, because refactoring/rename of type doesn't always work across multiple units. Then you end up with different names for the same thing. How can that be better? Refactoring tools get these names changed very reliably. I don't understand why people are scared of changing names. If you aren't prepared to change names then your code will be a mess. 6 Share this post Link to post
Dave Novo 51 Posted June 18, 2020 @David Heffernan Which refactoring tool do you use that reliably will change some scenario where you have lots of places across lots of units where you had something like procedure SomeProc var myList:TList<TFoo> begin myList:=TList<TFoo>.Create then you want to change all places from TList<TFoo> to TObjectList<TFoo>. So the refactor would presumably change the variable declarations and the .Create calls across all the units. It really does not work reliably for us and we have lots of search..replace with invetiable 10 minutes of compiling churn to get it all right. We tend to do TFooList=TList<TFoo> and just use TFooList everywhere for this reason. If the refactoring tools worked well, it would make that less necessary. 1 Share this post Link to post
Mike Torrettinni 198 Posted June 18, 2020 50 minutes ago, David Heffernan said: Refactoring tools get these names changed very reliably. I envy you. I don't have the same experience as you do, renaming across multiple units regularly fails on my Delphi 10.2.3, unfortunately. It's probably my project design contributing to the issue, but still, the IDE should be managing this better or alert on complex unit design if it bothers it. Share this post Link to post
Mahdi Safsafi 225 Posted June 18, 2020 As long as the compiler allows compiler directives... There would be no reliable tools. Share this post Link to post
Vandrovnik 214 Posted June 18, 2020 1 hour ago, Mike Torrettinni said: I envy you. I don't have the same experience as you do, renaming across multiple units regularly fails on my Delphi 10.2.3, unfortunately. It's probably my project design contributing to the issue, but still, the IDE should be managing this better or alert on complex unit design if it bothers it. In 10.3.3, it is better, usually rename finds all places, but sometimes it does not and finds for example just 10 of 30. Share this post Link to post