Detect if unit is used in interface or implementation only lazarus / 9-Editor ---------------------------------------------------------------------- Eugene Loza · 2024-07-28 14:39 There's an extremely useful feature in Lazarus: Source -> Refactoring -> Unused units. However, it doesn't consider if the unit is used in interface or implementation. I wonder if there is any way to do so automatically? It may be good to "lower" a used unit to implementation only if it's not used in interface, in context of cyclic dependencies in the first place. ---------------------------------------------------------------------- Joanna · 2024-07-28 15:00 That’s an interesting feature that I didn’t even know existed. I just looked at it and it seems to sort the unused units by interface or implementation sections  and buttons to remove the units. ---------------------------------------------------------------------- Eugene Loza · 2024-07-28 15:25 Indeed. But let's say we have Quoteinterface uses Classes; implementation var   MyList: TStringList; it will say that Classes is used (providing TStringList), however, it is added to "uses" of interface, while used only in implementation. And that's the issue I'd like to autodetect. E.g. in the example above it doesn't matter, but in case: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1;interfaceuses Unit2; type TClass1 = class(TObject) end; implementationvar  C2: TClass2; ... unit Unit2;interfaceuses Unit1; type TClass2 = class(TObject) end; implementation var  C1: TClass1;  we get a cyclic dependency error which in this case can be easily solved by moving uses from interface into implementation and potentially should be very easy to detect with something very similar to unused units. ---------------------------------------------------------------------- Martin_fr · 2024-07-28 16:37 1) With regards to unit cycles => menu: View > Unit Dependencies. Then the "project and packages" tab. In the upper graph select the package (or project) to view. Red lines go backwards. 2) uses in implementation. Personally, I prefer to keep all uses in the interface (even if only needed for implementation). That means, if I decide (against my own better judgment) to allow a circle, I have to deliberately change the "uses". I can't accidentally add a circle. But also, it avoids errors like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit MyUnit;interfaceuses SomeUnit; // Defines TFoo  procedure Foo(Bar: TFoo); implementationuses OtherUnit; // Contains a different declaration of TFoo procedure Foo(Bar: TFoo); // fails to compile, because it is a different TFoo, from OtherUnit.beginend; end. ---------------------------------------------------------------------- Joanna · 2024-07-28 23:39 The adding units to interface by default definitely makes more sense for readability. The implementation section often requires some scrolling to get to. So here is a question, if unit1 uses classes and unit2 uses unit1 and also uses classes , can unit2 use the classes unit declared in unit1 instead of having classes unit in its own uses section? Logically it should work but if it does it’s bad to not have everything that unit2 uses visible at top of unit. ---------------------------------------------------------------------- PascalDragon · 2024-07-31 21:04 Quote from: Joanna on July 29, 2024, 01:39:24 amSo here is a question, if unit1 uses classes and unit2 uses unit1 and also uses classes , can unit2 use the classes unit declared in unit1 instead of having classes unit in its own uses section? Logically it should word but if it does it’s bad to not have everything that unit2 uses visible at top of unit. Every unit must have any unit it directly(*) accesses in one of its uses-sections. That's the whole point of the unit concept, so that it's clear what a unit uses (for both the user and the compiler). (*) There are some exceptions, e.g. if you use a type only indirectly like here (note: this is a stupid example that has a memory leak, it's only to highlight the indirect use): Unit utest.pp: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit utest; {$mode objfpc}{$H+} interface uses  Classes; function Test: TStrings; implementation function Test: TStrings;begin  Result := TStringList.Create;  Result.Add('Hello World');end; end. Program ttest.pp: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program ttest; {$mode objfpc}{$H+} uses  utest; begin  Writeln(Test.Text);end. As you can see the compiler knows about the methods of TStrings inside ttest despite not having Classes in the uses-clause. If you'd want to store the return value of Test however you'd have to declare a suitable variable and thus declare the Classes unit in the uses- clause. ---------------------------------------------------------------------- cdbc · 2024-08-01 05:43 Hi @Joanna: If need be, you can /forward/ a type, by aliasing it in the unit, e.g.: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit utest; {$mode objfpc}{$H+} interface uses  Classes;//////////////// here /////////type    TStrings = classes.TStrings; // alias/////////////// function Test: TStrings; implementation...Regards Benny ---------------------------------------------------------------------- Joanna · 2024-08-01 07:34 That’s an idea