I'm pretty new to Delphi and I'm trying to use the DEHL Collections library. (see http://code.google.com/p/delphi-coll/ ) I'm have a little trouble with it from the IDE perspective. It compiles and runs correctly, but Delphi XE shows errors anywhere I use the HashSet library. The biggest grievance is that is prevents me from using code completion.
The first location I get the error is in an object declaration:
uses
SysUtils, Windows, Collections.Base, Collections.Sets, Collections.Lists,
adscnnct, adstable,
uOtherClass;
type
OneClass = class(OtherClass)
private
_bad: THashSet<string>; // THashSet underlined
_good: TList<string>; // No problems
end;
The error states: "Type arguments do not match constraints"
I don't think it's configuration as I can use TList just fine, but here is how I set it up: I've copied the library to Projects/Libs/DeHLCollections/Library and compiled the library to Projects/Libs/bin. I've included the bin directory in my global library path, which got it to compile and run. I have tried adding everything (/libs, /DeHLCollections, /Library) to it as well in hopes of getting the IDE to help me out, but it doesn't seem to be helping.
Anyway to fix this, or do I just have to deal with it?
Using DeHL Collections version 1.1.1.119
Welcome to the troubles with using Generics laden code. DeHL and generics work a lot better in Delphi XE than in any previous Delphi version, but that's not the same as it "not having any problems". The problems I experience are exactly like yours.
My opinion is that DeHL shows every sign of having been written by a master delphi programmer, and that it's a thing of beauty, in some ways. It's also a source of great pain, through no fault of its own.
Delphi contains not one or two, but at least three (maybe four?) separate parsers, including the full compiler parser, and a few IDE-parsers used for things like Error Insight (the errors you see even before you build) and the code completion data parser. Each has different language support limitations with regards to generics. It is possible perhaps that DeHL could be written to avoid parser problems with all the various Delphi parsers. I have not seen a guide ever written that shows the limitations, but I wouldn't be surprised if complex type declarations in the form TSomething<TSomething<ISomethingElse>,TBar<IFoo>> breaks more than a few of those parsers.
If you intend to use Generics very heavily, you may as well turn off Code Completion and Error Insight. You might also want to save often, and be prepared to experience a lot of compiler problems. And don't try to compile generics-heavy code and put it in packages either. I have experienced a lot of URW and AV (internal compiler faults) when I write generics based code. I find that the Delphi compiler team is great at fixing whatever gets reported, but that the Generics are really most stable for me when I restrict myself to using the Generics.Collections that come with Delphi, and not using other generics based code. It seems it is possible to write stuff using the generics features, that the IDE and two-way tools, and code-completion is not yet fully ready to handle. That means, phenomenal cosmic Generic powers come at a cost to the classic RAD IDE productivity features.
That being said, the latest DeHL sources from Subversion work fine for me and build and run with no errors, but the most recent source ZIP of the entire DeHL collection had problems for me.
I expect that over the next few releases of Delphi, whatever issues have been found (and DeHL seems to be a great place to push the boundaries, and that's one of the reasons i'm a big fan of it) will be fixed, and you won't be wondering why heavy-generics break your IDE features, because they'll all be working again.
Related
So, I have a myself written run-time package. If a package is statically linked, the project that uses has full access to exported data because the compiler has full knowledge of what is imported from it, am I right? But it's also possible to load a package dynamically via LoadPackage(). But, how to work with imported complex data structures like classes then? I couldn't find a feasible way other than constructing complex expressions like using FindClass('TSomeClass') and invoking RTTI to operate on an instance of the imported class.
The compiler has full knowledge of what's in the package because the DCU and DCP files tell it what's there.
The IDE knows what's in the package because it knows how to find the Register procedure in all the units, and that procedure tells the IDE about the available classes.
In most cases, a program knows what's in a package because the program used units from that package, and the compiler assured that mentioning names of things in those units would resolve to corresponding things in the BPL file at run time. This includes mentioning the BPL file in the program's import table, so the OS loads the BPL automatically.
If the list of BPLs you wish to load can only be determined at run time, then you cannot use any units from those packages. You have to load the package dynamically.
There's still the matter of how to use what's in those packages. You could try to discover the entire contents with RTTI. That's no picnic, though. Instead, define an intermediary package that all involved modules will use.
Define an interface or a common base class for all your packages' classes to have. Put the definition of that class in a unit that's in its own package, which we'll call Shared.bpl. Include that package in the "requires" list of all your other packages and your EXE. Now, everything can refer to the shared unit and the common base class.
This is exactly what Delphi itself does. The shared packages are called RTL and VCL. There are several common base classes already defined there, including TComponent. In your case, it sounds like you need some common definitions beyond what TComponent has.
Short answer:
What you need is the compiler/linker to set you up and use DCPs to do all the linking to types and such.
Then loading of BPLs should be delayed/done by you in custom code.
Unfortunately Delphi won't allow this, probably because of political reasons, you could try and hack it though, see below for more thorough answer.
Long answer:
Apperently DCP describe to the compiler/linker/Delphi yadayadayada what's in those packages/DLLs/BPLs type-wise.
These DCPs can be considered the interface to these DLLs/BPLs, these DCPs are probably somehow compiled into the executable.
Then the BPL probably contains the "implementation".
Now here is where the problem begins. These BPLs are "auto-loaded" as somebody else already mentioned by mentioning "import table".
What you could try is "nuking" / altering the import table so that these BPLs are not loaded automatically anymore.
Then you could try loading these BPLs manually.
I am not sure if it's just as simple as doing a "load package" operation.
Perhaps the loading involves more like acquiring pointers to routines/methods/classes, not sure how that works.
However perhaps that code can be re-used, so all you need to do is "hack" into the import table and hack into the "load bpl" and disable it.
Then you should be able to replace that with your own custom loading code and perhaps finally "re-patch" into other importing routines... like routines calling getprocaddress and such if so required, not sure about this last part.
Anyway this is very sloppy from Delphi developers that there is no functionality to do this little "import table"/"load step" yourself.
This is politics at play though, there is no technical reason why this could not be delayed, done custom by you and then call the rest if necessary.
For some reason they do not want you loading these BPLs manually. They probably want you to keep using the IDE this way.
If you were able to load these things manually, maybe the IDE would then no longer be necessary.
Currently the IDE is necessary to specify where to load this stuff from, without the IDE it will get difficult. Though there are probably also some compiler options somewhere to specify the same, though few would use that.
So to me it seems some very weird "tie-in" into this product, which I honestly must admit is pretty fucking retarded.
They did the same with winsock for example which has two different versions, very easy to load this yourself manually so you can choose which version to use instead of always v1 or v2. For easy for them to delay these getprocs and such, yet they do not...
If they did, Delphi would be much more backwards compatible with windows 95/98, currently Delphi exes no longer works for those older operating systems, though there is no real technical reason why it could not work, it basically has to do with which DLLs are loaded, just a few lines of code could very easily make it work.
This is probably again politics as play to make Delphi only support the latest Windows versions a deal struck between Delphi creators and Microsoft.
Same thing with Windows 10, it apperently detects older processors and then refuses to run on them, removing/hacking these few lines of code/instructions will make Windows 10 work on older processors. Surprise ! =D
In our team new programmers does not get access to all the source of our application.
As long as they have to access program forms that depend only classes they can access the source, all is ok. When they have to use other classes from units they have only the .dcu, they get the F2051 error when the classes in the dcu change their interface.
Is there a clean way to get both ?
possibility to hide part of the source from new programmers
avoid the F2051 error when the classes in the "hidden" units change
I searched for a way to compile the Delphi code to a intermediate representation the way to hide the sources but to permit compilation, but I did not find anything.
You have to compile the code after the interface changes, and distribute the new .dcu to each programmer that needs to use it without source, and then they need to rebuild their applications. There is absolutely no other way to do it; the compiler requires it if there are changes in the interface.
For those "hidden" units, put the .dcu in the source control along with the .pas and make sure they are updated and in sync.
The "authorized" developers will fetch the new .pas, while the underlings will only see and fetch the .dcu.
If you really want to go that route of having 2nd class programmers, you have to do the management work that go with it.
That being said I'm personally more often that not stepping into the VCL source code when chasing a bug and trying to understand what's going on.
And I really don't like not having it (like with some low level Delphi SKU)
If you really want to create a stable binary unit that you can share with people you don't trust to read your source code, why don't you put the "secret" bits into a DLL and then load that DLL from the rest of the code.
It's called an "Application Binary Interface", either done natively with plain old pascal procedures exported from a DLL, or with COM Interfaces and a COM type-library.
Delphi has both DLL and BPL technology, to help you create something that isn't source code, but which has a stable ABI, and which will help you avoid whatever crazy little mess it sounds like you've got on your hands right now.
http://en.wikipedia.org/wiki/REPL Read–eval–print_loop
Is there such a thing for Delphi ?
It would be rather useful to explore DLLs such as Windows APi and sketch their usage, when dealing with border cases scarcely documented.
I tried pascal scripts, such as one in Cnwizards, but it is much less comfortable.
For example it cannot use units like Windows.pas and you had to make some strange stubs of your own for it.
And anyway, those scripts are less easy to use for "try this try that" scenario than Repl.
For Delphi objects most clsoe thing it to pause on breakpoint and use Evaluate/Modify window, but it only works with Delphi objects, not DLLs; it cannot make temporary vars to cache values and such.
It's not really what you're looking for, because Delphi is a statically typed, compiled language, but if you really insist on being able to type some pascal in and see if it does anything, you can try the TJvInterpreter component that comes in the Jedi VCL.
Note that the experience is nothing like using python. You can't just type "uses module" and hit enter, because pascal units must be complete before they can even be interpreted by JvInterpreter, and the JvInterpreter needs you to write a wrapper for every single other unit you want to import. You would go crazy. I'm not seriously advising anybody to try to build a REPL around TJvInterpreter.
The "interactive magic" element of Delphi is called the "designtime environment" and the way we build using "components". We don't even do that bit by writing code much, we do it all visually with our mouse and keyboard. It's called RAD (rapid application development) and is powered by the VCL (visual component library) in Delphi, and (like REPL) is one of the many ways of doing very-rapid development.
The other thing we have that is a lot like a REPL is this button in Delphi:
You click it, after creating a new empty project, and whatever code you added to your new empty project is built and running in less than a second. Close enough to a REPL for me. It's kind of like binary executable instant bliss.
Write one line. Build and run (1 second). Instant.
I am doing some refactoring of my Delphi project. I want to be able to make a change, then see all the places in the project that break due to that change. Similar to how Eclipse lists all the compile errors for a project (in Java).
In Delphi, I can make a change, then recompile my project, but the compiler stops when it finds the first Unit that does not compile. I have to fix that Unit, compile again, which will then show me the next error, etc etc.
I want to be able to see all the compile errors in the project at once. Then I can decide if the change is worth doing or not. For example, if the change will require hand fixing of 50 separate source files, it's not worth doing. But if it only breaks 2 files then that's an easy change to make.
Is there any way to do this in Delphi? Can I tell the compiler to keep going even after finding a Unit that does not compile?
I am using Delphi 2010
Delphi units, as a modularity feature, are conceptually at a similar level to Java jars or .NET assemblies; they compile to individual files. In neither Java nor .NET can you compile dependent modules when you have compile errors in a referenced module.
The reason they are more granular than .NET assemblies etc. owes to their history. They were designed in part around the segmented x86 architecture; the data associated with any one unit could not be any larger than 64KB. Similarly, units served as a natural division between near code and far code. If you're familiar with 16-bit x86, you'll know that pointers to far data required a value for the segment as well as the offset, while near data only needed an offset. Calling near code was also faster than calling far code. Programs were also smaller and less complex back then; the unit was a reasonable granularity of module for an entire subsystem's worth of behaviour. This is much less the case today.
There's no way to do that with the Delphi compiler, but if you're considering making a breaking change to some part of a unit's public interface, you can use the refactoring tools that come with the IDE to find all references to whatever it is you're about to change before you change it, which will give you the information you're looking for.
The Delphi compiler already tries to compile as much as it can.
Unfortunately, very often, an error is critical enough to prevent the compiler to move past the error as it cannot make an assumption as to what the code should be it if were compilable.
Moreover, very often, the errors a compiler can give after the 1st error has been encountered are not reliable and may even disappear after the 1st error has been fixed. (witnessed by all the red squiggly lines appearing and disappearing when you type)
What the compiler does however is to provide all the hints and warnings (which are called errors for some other compilers).
You can use Ctrl-Shift-Enter to see all occurances of the variable, property, method or wahtever is currently under the cursor. With that information you can decide to do your changes or not.
Alas, with the current version this feature doesn't work as reliable as it should.
I'm pretty frustrated. I'm using Delphi 2009 and was very happy about the inclusion of generics in this version of Delphi. Everything worked great at the beginning, but now that I use generics all over the place I run into problem after problem - most of the time some internal errors, where I don't even see where exactly they are caused. I tried restructuring the code multiple times to avoid the problems with generics but always run into new problems further down the line.
Now I decided to remove generics alltogether and use some dynamic casts to specialize my classes. Not very thrilled about it but i just don't see another option. I can't spend my day tracking down Delphi's internal compiler errors...
Is anybody using generics in a large project without running into such problems? Is it my fault perhaps? Or is it just not possible to use them in complex projects?
I hope D2010 fixes all this stuff.
I'm using generics extensively in Delphi 2009, and I can say it's not easy as you are often required to work around an ICE. Even worse, generics even mess up with the linker, i.e. you can't really use them in packages (except for C++Builder packages).
All this trouble seems to be gone in Delphi 2010; I hardly ever saw an ICE due to generics. I need my code to work with both 2009 and 2010 though :(
Generics support in D2009 was really bad at first. Update 3 fixes a lot of things, but not everything, and leaves at least one serious bug in Generics.Collections.pas. In some ways, it actually got worse, since now instead of giving you a syntax error when the compiler chokes on some generic construct, you'll often get an internal compiler error and you don't know what's causing it.
It's been improved quite a bit for 2010. There are still a few generics-related problems in rather obscure cases, but they're generally safe to use as long as you're not using packages or putting generics inside of class helpers or strange things like that.
Bottom line: if you want to use them, upgrade to 2010.