The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,259 other subscribers

Delphi: removing “unused” units from uses lists cannot be fully automated (via: SO)

Posted by jpluimers on 2014/11/11

One of the things a lot of Delphi users want is to be able to automagically remove unused units from their uses lists and projects.

The short answer is: you can’t.

The long answer starts with: you can’t fore a number of reasons.

Similar reasonings hold for many other development environments. Plain Windows EXEs and DLL dependencies. .NET projects and assembly dependencies, etc.

Initialization/Finalization dependency

The first reason is that each unit (module, assembly, or other dependency) can contain global code to be executed at unit start/load or finish/unload.

So even though you do not reference anything inside that unit, the initialization and finalization sections can be run.

Removing the dependency from your units and project, kills that functionality. And might break all sorts of things.

Load order dependency

Sometimes you have subtle load order dependencies of units. Those should be rare, and if they are there, should be enforced by the affected units themselves. But everyone knows those subtle dependencies are more often a by product not enforced by anything than coincidence.

So if you start removing references, the load order might change, and subtle bugs may occur.

In other words: test, test, test and test your codebase before and after removing unit references from uses lists.

Parsing

If you understands the dependencies of initializtion/finalization or load order, you will get interested to know what units are actually being used.

The ultimate source for this would be the Delphi compiler. Bad luck here: you cannot use it as the IDE and command-line interfaces don’t offer a hook to it to do just this.

So you need alternative parsers that can help out. The answers to How to remove unused units from all source files on Delphi XE2 describe a few and they all have the same drawback: they are not the Delphi compiler, so they are a rough approximation of what the compiler would do.

And even if the approximation would be perfect, they all suffer from the same thing the compiler suffers from: you can only have one set of conditional defines, platforms, etc at the same time.

There is lots of code for which the usage is conditional, but where the uses list does not reflect this.

Fazit

Optimizing uses lists to eliminate unused units seems a simple thing at start, but isn’t.

The best way to keep those optimized is to prune them while developing. So if you remove code, try to remember cutting down the uses lists by hand.

And then test, test, test and test your codebase.

–jeroen

via: ide – How to remove unused units from all source files on Delphi XE2? – Stack Overflow.

8 Responses to “Delphi: removing “unused” units from uses lists cannot be fully automated (via: SO)”

  1. Eric said

    RTTI and dependency injection can also be a major source of dependencies that can’t be removed, as classes and code may then only be statically referenced in the initialization blocks, their units could appear as “useless” in a static analysis.

  2. RedDragCZ said

    I just can’t agree.

    From my point of view, code that depends on the order of the specification of it’s unit dependencies would most certainly be considered as defective. And relying on initialization/finalization of global things from the outside of the unit is just as bad as with almost any globals… just, don’t. (And if I actually had such specific case, I wouldn’t use the remover on that unit.)

    I get the fact that sometimes, you may encounter similar cases, where the code of rerefenced units is simply BAD, but that doesn’t give any basis for declaring these as general rules.

    • jpluimers said

      Even though it is indeed bad practice to depend on unit initialisation order, memory managers, the VCL and FMX depend on it, so sometimes you have to rely on it.

  3. Silver Warior said

    I think that the main problem is that the Delphi code editor still treats code units as large blocks of code as it was common in the time before OOP languages even emerged instead of treating actual code blocks as such.

    By redesiigning the code editor in a way that it treats actual code blocks as such you would get ability not only to determine which units are being used but even which specific methods, variables, constants, etc. are being used no mater if these are used in initialization, finalization or implemetation sections. And the best thing is that such information could be available at all times and not only on compilation.

    • jpluimers said

      I think you hit the nail right on the head.

      • Silver Warior said

        I did did I :-)

        Now let me ask you a question. Do you think Embarcadero would be interested in rewriting the code editor so that it would threat the code blocks as such?

        You see when I think about this I belive that code editor that treats code blocks as such could bring lots of usefull features like:
        – ability to create and maintain code dependancy tree
        – ability to create and maintain code flow graph
        – ability to compile finall build where only parts of code that are realy in use are compiled into finall executable. This would greatly reduce the size of the executables generated by Delphi.
        – ability to integrate unit testing where the editor will automatically take care about which unit tests needs to be redone based on code changes you made
        – if properly integrated with unit testing you could even get nice anbd powerfull code time profiling system. And if you return that information back to the IDE you can use it to dynamically size the flow graph nodes which would alow you to visually find the code botlenecks. This could even become usefull in multithreading as you would get better perspective on how much time each thread uses for its work.
        – ability to full integrate source versioning like git with full capabilities including branching
        – treating code as true code blocks would also enable you to more easily detect code scopes which could be verry helpfull for speeding up the Code Insight and Error Insight not to mention that it would surely alow easy fix for some bugs that these two systems currently have (code below cursor automatically expanding when sytax error is detected by Error Insight, Slow code insight in project with lots of large units)
        I bet there are lots of other benefits such system could bring.

        Now the only problem I see for this are Generics. Why? By design generics are made in a way that at design time you don’t know whit what objects or types will you be operating and therefore you don’t know which code would be needed. So the new ediotr would need to have a special system which would alow developer to decide which parts of the code would be available for generics.

        • jpluimers said

          I hope they would be interested.
          Generics should not be a problem, as the AST should make clear when they are being typed or not.

  4. CN Pack wizards has a Uses Cleaner which i find very effective

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.