[ Page 1 of 2 ]
From: Phil!Gregory Date: 22:08 on 25 Aug 2006 Subject: Delphi. Excessive type-bondage. Allow me to quote from the Delphi help file: For a variable parameter, the actual argument must be of the exact type of the formal parameter. procedure SwapBytes(var B1, B2: Byte); var Temp: Byte; begin Temp := B1; B1 := B2; B2 := Temp; end; var C1, C2: 0..255; (*Similar to a byte, but NOT identical*) begin SwapBytes(C1,C2); (*<-- Error message here*) end. Arguments C1 and C2 are not acceptable to SwapBytes, *although they have the exact memory representation and range that a Byte has*. [Emphasis mine.] Oh, and for the case where I specifically ran into this, typecasting won't help. Apparently when you typecast a variable, the result looks like a constant to the compiler so you can't pass it as a variable parameter (pass by reference).
From: Phil!Gregory Date: 17:37 on 12 Aug 2005 Subject: Delphi's Type-Bondage Hey, here's an idea. Let's make a language that forces the program to adhere to extremely rigid variable typing rules. That way, we can force the programmer to never shoot himself in the foot. Oh, but the whole bondage and discipline approach to typing won't make him hate us enough. Let's also introduce just enough type interchangeability to break anything where he might try to use the type strictness to his benefit. Well, it works. I hate them. I have to read a series of database fields into a series of variables. Except for the types of the variables, the process is the same for all of the fields. I'd love to have just one function to call on all of them; it would make things very simple. Delphi thinks differently. There's no way to to hand a function a variable of an arbitrary type and have it do the right thing; the compiler won't allow it. The best I can do is to keep track of the data types myself and pass an extra value into the function to tell it what the type of the destination variable is. "But wait!" you cry (maybe). "You can use overloaded functions and inheritance and stuff!" Or, at least, that's what I though to myself. But, while Delphi is ever-so-strict about keeping different types separate, if one type is defined in terms of another (TDateTime is really a Double, for instance), overloaded functions _cannot tell the difference between them_. Go, Delphi, giving me the worst of all possible worlds.  To the point where this is illegal code: var arr1 : array[1..10] of Integer; arr2 : array[1..10] of Integer; begin arr1 := arr2 because the compiler considers arr1 and arr2 to be of different types.
From: Phil!Gregory Date: 16:23 on 21 Apr 2005 Subject: More BDE Hate I would love to stop using the BDE. If only we didn't have so much legacy code that relies on it. The BDE sometimes needs to create temporary tables for intermediate data (often as a result of SQL queries) it does this in what it calls a private directory. (You need to set the private directory because if you don't the BDE will use the same directory that your executable is in, and that's bad, because it makes the lock files too large. I don't know why; it just does. But that's an old hate now.) When you initialize your BDE session, the session puts an exclusive lock on the directory. So you can't have multiple instances of your program using the same directory. Fine, I can deal with that. Oh, and if the program exits unexpectedly and doesn't unload the BDE, that directory stays locked. "Okay," I think, "since I only have one instance of my program running, I'll just have it delete any old lock files when it starts, since they won't be valid." What I learned is that the BDE DLL remembers the locks, so as long as any other program has the DLL loaded, I can't just restart my program. Needless to say, this makes developing and debugging the program somewhat painful. Program crashes, I have to go exit all other BDE-using programs on my system, then restart them, because I need to use them. Repeat every time the program dies while I'm working on it. Hate, hate, hate.  The BDE DLL is actually named idapi.dll. Go figure.
From: Phil!Gregory Date: 19:02 on 07 Apr 2005 Subject: Ugly Code I hate having to write ugly code. (Yes, this is another Delphi hate.) I like the fact that Delphi supports exceptions; they make error handling easier: try // code // code // code except on EFooError do begin // handle error end; end; Exceptions also necessitate cleanup clauses. In Delphi that's try...finally: try ... finally // cleanup end; Of, course, many times, you want to both handle errors and clean up allocated resources. This is where Delphi gets ugly: try try ... except on EError1 do begin ... end; on EError2 do begin ... end; end; finally ... end; And don't forget that if you raise an exception in a finally clause it clobbers the preceeding exception: try try ... except on Exception do begin ... end; end; finally try ... except on Exception do begin ... end; end; end; Ugh. Not to start any language wars, but there are other syntaxes that I find much more attractive. For example: (if (null (catch 'exception (unwind-protect (code) (cleanup)))) (handle-error)) (Granted, it's less structured than Delphi, so the programmer has to impose his own structure, but it *looks nicer*.)
From: Phil!Gregory Date: 21:09 on 20 Aug 2004 Subject: Delphi, Printing Right now I hate printing and I hate Delphi and I hate printers. Most printers we have at the office are smart. You hand it an 8.5"x11" thing-to-be-printed and it says, "Oh, that's letter-sized paper, which is in tray 2, so I;ll use that," and everyone's happy. I now have to deal with one that's dumb. It must be told which tray to use, for it it a simple printer and cannot figure these things out on its own. So my program must offer the user a choice of available trays and then pass that choice to the printer. And I can do that for some things, though I have to muck with the Windows API because Borland didn't feel like adding support in its TPrinter object. But I also use Quick Reports (comes with Delphi), and while it has a Tray setting, it's a predefined enumeration for which there's no good on-the-fly mapping to the actual printer's trays. And no way to provide arbitrary input on sending to arbitrary trays. I also have to print through Word. Its OLE interface doesn't seem to have any provision for tray selection. Hooray for not having standards. Hate, hate, hate.
From: Phil!Gregory Date: 21:42 on 11 May 2004 Subject: Charset Abuse Okay, getting everyone on a single, encompassing character set/encoding is pretty much a pipe dream. But why can't tools at least communicate what charset they're using? I'm used to getting web paged that misreport their charsets. When I read things like "I m sure it s ok", I can generally tell w3m, "Ignore what you were told; this page is in CP1254." This doesn't work if the content was written in CP1254 but the publishing tool turned those 0x92 apostrophes into ’ HTML entities, which is just wrong. This isn't really a rant directed at any one thing in particular. I just wish all this stuff with character sets happened transparently and that I wouldn't have to have learned what little I do know about the whole process. Like so many things, it should just _work_.
From: Phil!Gregory Date: 22:28 on 10 May 2004 Subject: Modifying Constants A minor thing, really, but I've just wasted several hours on this bug: I've been working on convincing a Delphi program to call procedures in a DLL. This is new to me, so I figure I'll do things wrong. Thus, when things go wrong, I blame myself, sometimes, as I found, needlessly: procedure SimLibLogon(pszDBName: PChar) external "EKDWS.DLL"; procedure DoStuff; var System : String; begin System := 'VADER'; SimLibLogon(PChar(System)); end; and I get an access violation. The problem? Delphi is stricter about types than C. So, with the prototype I wrote for the procedure, Delphi decides that the string is a constant, and just calls it with a pointer to wherever the program stores its string constants. The DLL was written in C. It gets a character pointer which, logically, ought to be constant, but isn't strictly so. It tries to modify it. (Consensus here is that it's probably trying to upper-case the string.) The string is in non-modifiable memory, so I get an error. I blame myself, try to fix it, and run in circles for a couple of hours. Solution? System := Format('VADER', ); Compiler has been fooled, and the string is now in modifiable memory. Sigh.
From: Phil!Gregory Date: 03:21 on 22 Apr 2004 Subject: Final Fantasy XI Yes, Final Fantasy XI is a game. But it's software, too. And right now I hates it. Sony did a system upgrade today, which means that all the client programs have to download updated data files. (In my case, they're downloaded to a hard drive on a PS2.) Not surprisingly, the servers are a little busy serving out the updates. But let's look at how the system fails. The first indication of a problem is an error message that says roughly, "There was a problem connecting. Perhaps the server is busy or the network isn't working. Make sure the Ethernet cable is connected properly." I know from tcpdump that the PS2 is communicating quite well with the server--the local network is *not* a problem. Don't give me a message implying that it is when you know better than that. Then, the upgrade. After hitting retry a few times, I get a slot and it grabs the checksums for the current files. It then takes about seven minutes to check that all the local files are okay. Once that's done, it tries to connect to the server again. If it fails at this point (very likely), it starts again from the beginning--file verification and all. *Very* annoying. The software should be smart enough to pick up where it left off. About the only argument I can think of for this problem is that it enforces a delay in retries and probably lightens the server load a bit. But that could have been done more effectively via any number of processes--look at the verious solutions used by P@P software. A download queue or torrent would have been a lot nicer to deal with.
From: Phil!Gregory Date: 22:17 on 14 Apr 2004 Subject: MS Word Collating Multipage Mail Merged Documents I don't want too much. I have a 6-page mail merge document. I want to do a merge and then print multiple copies so that all of the pages for the first person's first copy are printed, then all of the pages for the first person's second copy, and so on. With Word, I can either print one copy for each person before going back and printing a second copy for everyone (collated) or I can get all the copies of the first person's first page followed by all the copies of the first person's second page, and so on. You'd think they would have thought of this. Even if there's a limitation in the printing interface (though "collate in groups of N pages" shouldn't be _too_hard), you should be able to order the output of the mail merge to achieve the desired effect. But no. I have to mess with the data going into Word to get what I want. What I get for using the program in the first place, I suppose.
From: Phil!Gregory Date: 21:37 on 22 Mar 2004 Subject: Hey, more BDE hate! So thoroughly fed up with Delphi and the BDE at the moment. Possibly also Client Access--I'm not sure where the hate truly belongs. Programming in Delphi 5, using the BDE, accessing tables via the ODBC driver in Client Access to get to an AS/400. A little while back, the DBA created a ten digit numeric field to use as a key on several tables. The most significant digit of the field indicates the source of the number (1 if site a generated it, 2 if site b did, and so on). It worked when only two locations were generating values. (See where this is going?) When we added a third site, everything broke. 3E9 is larger than 2^31. I'd been using signed integers in Delphi to hold the value of the field. I switched to using Int64s. Everything broke again, but in different, more subtle ways. TTable.FindKey doesn't work if you hand it an Int64 value. It's not a type it looks for, so it causes an error. TDataSet.Locate (and other, similar methods) doesn't work, because Int64 is the *only* type that cannot be put into a Variant. Using SQL to find a record worked some of the time, but sometimes spun the program off into a series of access violations deep in the bowels of the BDE code. I tried telling the program that the field was really a String, not an Integer. Didn't work. Base field type is provided by the underlying database driver. Client Access said it was numeric, so it was numeric. I tried Googling for information to see if this was a known problem, to see if maybe it worked better in newer released of Delphi. No information. As far as I can tell, no one has run into this problem before (which is pretty unlikely). The solution was to alter all of the tables that had the offending field, fix the values of those fields to be 9 digits, change the Delphi program back, recompile all of the programs on the AS/400 that used the affected tables, and erase all thought of ever again using an Int64 for database access in Delphi. Simple, no?
[ Page 1 of 2 ]
Generated at 10:28 on 16 Apr 2008 by mariachi