[2001-08-16]
This is where I will put asorted rants of mine. I will lash out at anything and anyone, the only reason being I feel like it and that I want to make myself feel better. Since I'm a computer-geek many things will revolve around that type of thing, as you can see from the headings below. Because of this (and this pages heritage) I have also squeezed in a little section called resources below. If it'll ever come to grow, it might get it's own page somewhere else.
So, without further ado, I give you, the rants; Miscellaneous, Visual Basic and Java. Remember, these are my rants, they may or may not represent actual facts. Send any comments to me at srm_dfr@hotmail.com. I'm especially looking forward to receving corrections. I am after all doing this to increase my and others knowledge, not to look/stay ignorant.
First, let me say that this section is totally outdated. When I wrote this I was using VB5 for starters, and I have nooo idea of what might have changed with VB6 and VB .NET or whatever the latest version is nowadays.
I'm documenting some of the hurdles I've leapt as far as VB development goes. I hope that this will provide a valuable service to other programmers. When it comes to developing under Visual Basic I'm pretty torn. On one hand, it's nice to be able to rapidly build a pleasant (to the eye) application skeleton, but on the other hand I'm constanly running into the barriers of VB. There's just too many things you are not allowed to do (mostly low-level stuff, the availability of which is absolutely vital for someone like myself). Here's some of the problems I've faced:
This I have not solved yet. The best solution would be a function which could translate VB's internal filenumbers into their windows filehandle counterparts, making it possible to truncate a file using the system32 function SetEndOfFile(), or to simply replace all internal filehandling functions.
Picture this: You have a hundred different forms, all with unique names. You also have a database, in which each record contains - in a field - the name of the form associated with it. Problem: Use this field to load the correct form from VB - without hardcoding the link between the names in the database and the forms available in the project. What it all boils down to is that a form that is not loaded also is not present in the Forms-collection, and a form not in this collection cannot be referenced in any other way than using its absolute hardcoded name. The only "solution" seems to be taking the round-about trip of using a gigantic select-case statement. Very ugly.
Update 2001-08-16 - Mike Cross sent me the following:
Well, there is a way (one of Microsoft's Hidden "features") if you treat an app's forms as a collection: Dim sFrmName$ Dim frmTemp As Form sFrmName$ = "Form2" 'Or whatever you want Set frmTemp = Forms.Add(sFrmName$) frmTemp.Show
However, I have no idea if this would work in VB5. And really, I couldn't care less anymore :-)
Apparently the statement "const bArray(1 to 2) of byte = 65, 66" makes no sense to Microsoft. Well, it sure does to me, and I want it. Specifically my problem is that I have a binary resource that I want linked with (as into) the executable. In languages such as Pascal and asm you would either use something like 'incbin <filename>', if available, or create a program that take a binary file as input and outputs the source for an array-constant representing that data. As array-constants isn't available in VB the closes solution would be to create the source for lots and lots of assignments into a byte array, however, this "solution" is simply too wasteful to be useful. It's very likely that using resources (.rc) is the solution to this problem. I have not yet found the time to test that approach.
Why Microsoft chose this way of doing filesearching I have no idea. It's the least elegant way I've ever seen (and I've been doing the same thing in 16-bit asm since the early 90s!). The OS itself (DOS/Windows) use a concept of search-records, a simple structure used for specifying what you want to search for and later holding the result of the search, issued using FindFirst() and FindNext(). In languages such as Pascal (or assembler) you would simply declare a new such record (called DTA, Data Transfer Area under DOS) and feed it to the FindFirst() and FindNext() functions. For VB however, Microsoft chose to create a single thinned-down global search-record, thereby cutting down on both the versatility and elegancy, while gaining next to nothing in the department of efficiency or simplicity. There's Microsoft for you. The following example illustrates this:
A typical problem for new programmers is: 'how can I process all files in a directory and it's subdirectories.'. At first glance this might seem like complex problem, but actually it's quite simple. Recursion to the rescue. The logic goes like this:
1. Find the first 'file' matching the criteria (say '*.*') in the directory supplied.
2. If no file found, exit.
3. If the search resulted in a normal file, process it.
else
The search resulted in a directory, call myself (recurse) with
the found directory as the dir-parameter.
4. Find next file, loop to 2.
The beauty of which is best demonstrated by this example code in java:
public static void traverse(File f)
{
System.out.println(f); // process the file here
if (f.isDirectory())
{
String list[] = f.list();
for (int i = 0; i < list.length; i++) traverse(new File(f, list[i]));
}
}
Now, because Microsoft implemented Dir$ as a global search-record, this method isn't readily available. The recursion would use the global search-record instead of a new local one, yielding unexpected results. The solution to this is to emulate a stack (or similar datastructure). The new logic goes like this:
1. Create a new collection
2. Find the first 'file' matching the criteria (say '*.*') in the directory supplied
3. If no file found, exit loop (go to 6)
4. If the search resulted in a normal file, process it.
else
The search resulted in a directory, add that directory to the
collection
5. Find next file, loop to 3
6. Loop thru the collection, calling myself for each and every entry in it.
Here's some actual source from my toolbox:
Public Sub doRecurseDir(ByVal RecPath As String, ByVal filemask As String)
Dim s As String
Dim i As Integer
Dim pathlist As New Collection
If Right$(RecPath, 1) <> "\" Then RecPath = RecPath & "\"
s = Dir$(RecPath, vbNormal Or vbDirectory)
' find all files
While s > ""
' push directories to "stack"
If (GetAttr(RecPath & s) And vbDirectory) = vbDirectory Then
If (s <> ".") And (s <> "..") Then
pathlist.Add RecPath & s
End If
Else
call PROCESSTHEFILE RecPath, s ' Process file here
End If
s = Dir$
Wend ' .. while file found
For i = 1 To pathlist.Count
Call doRecurseDir(pathlist.Item(i), filemask)
Next i
End Sub
Notice that searching for just directories is broken (an old DOS legacy it seems), you must explicitly test for the vbDirectory attribute using GetAttr (again, in a real language, pardon the expression, the attribute would be readily available in the search-record).
One day I wanted to implement a CRC-32 algorithm in VB5. I started converting the
Pascal code I've been using for the past five years and so, only to smack into the biggest
wall so far. How can I do a bitwise shift right in VB? The answer: you can't. Not without
serious performance implications at least. Why Microsoft has omitted these two basic
operations (in fact, they are so basic that they have their own mnemnonics in the Intel
x86/Pentium+ processors!) I have no idea. Adding them should not take Microsoft
very long (it's a matter of hours, even if the VB grammar is as horrible as I imagine).
Using + and -, or multiplication/division isn't a viable option because a) There's no
unsigned long and b) Under/overflow can (and will) occur. I got overflows even after
turning off "integer range-checking" in the project properties. Maybe longs
doesn't count? Well, if you get it to work, please fill me in.
Anyway, after playing around, trying typecasting and various tricks to fix-up the
overflowing I simply gave up in disgust. I shouldn't have to go thru this simply because
Microsoft are lazy! What I did was this: I wrote my very own DLL (Dynamic Link Library)
using 32-bit asm, where I implemented the shift functions (a matter of three lines of
assembly). This is the best solution I've found, but it has the disadvantage of adding
yet-another DLL to your distribution/system, besides which; not every VB programmer have
the knowledge required to write their own custom 32bit assembly DLLs. Well, if you are one
of those, don't despair. Mail Microsoft and complain about the lack of lowlevel operators,
then grab your own copy of my DLL here. The archive
contains not only the binary, but also the source and instructions on how to build it
using TASM (assembling under MASM should be a trivial exercise).
Update 2001-08-16: It is of course possible to solve this using plain old VB-code. There's code out there, use a search-engine to locate it. My way of doing it above was more of a demonstration than a serious solution. Though it would be interesting to compare the DLL-approach to native code and see which is faster. There's always a little overhead calling the DLL, but it might win out after all.
Spent many hours debugging a program just to discover that the PM-field I read from a rdoResultSet were set to NULL after having been accessed once. As I was using the RS in a loop (like in "rs.rdoColumns.Item(j).Value", replacing keywords in a HTML-template with actual field-data from the DB) that behaviour was pretty much unwanted.. I don't know what is wrong, maybe I'm just ignorant, but neither my teacher nor his contacts could explain it. I ended up making a local structure to which I copied the data of the recordset, and then used that local copy in subsequent code.
Java is a wonderful and very beautiful language, but that doesn't mean it is perfect for every type of application, and hence I will always have something to rant and rave about.
Who the fuck decided to define a byte as 'signed' in java? Oh please, I have never used or even desired an integer datatype with the range -127 to 128. Have you? No, I thought not. Sure, there's 'long' and 'BigNum' and all that, but I'm sure someone capable of designing and writing OOP-code would be able to handle the minor hurdle of learning a "new" datatype prefix like 'signed'.
There are two major byteorders in modern microprocessors (and a couple of minor, used in ancient architectures), MSB and LSB. Motorola use MSB (aka "Big-endian"), and Intel LSB. Okay, so I'm over simplifying, but anyway. The thing is, somewhere along the design curve Sun decided that Java would use MSB externally (I'm sure the fact that Suns solaris-boxen are MSB had nothing what so ever to do with this decision). The small problem is that the Intel 80xxx and derivates are LSB. So what happens when you are programming java on the Intel platform is that you are using a language with a different endianess than the underlying architecture, which becomes a problem when you begin reading and writing to external datafiles meant to be shared between lot's of different applications.
Now, I understand that java's meant to be platform independant, but I don't think that little feature should go overhand to the point of exclusion of platform dependant features. Let me explain: When java write a word to a file it's stored as bytes in the order HHLL. When a native intel-program does the same, it will write LLHH instead. Obviously this will result in an error if one program (native) writes a word, and another (jvm) read it. Since we know that the Intel platform is LSB and the JVM is always MSB, then obviously the JVM is doing a conversion somewhere ($1234 is stored in memory as $3412 due to platform being LSB, but to file as $1234 due to javas endianess - must have been converted somewhere). This is a performance hit. As you know, java isn't that fast to begin with, and it doesn't get any better when I have to override a whole class of methods just to shift-around bits to get them in the right order - in effect reversing the conversion already done at another level!
What I propose is a JVM configuration option (accessable in java) that can be toggled between: platform-default, MSB-always and LSB-always. This would control how the JVM will handle integer datatypes as they are read and written to file, possibly saving programmers around the globe a lot of work and resulting in increased performance. Sounds like a win-win to me? Notice how it wouldn't even break portability. It could default to MSB-always, but if the programmer know that this program is interfacing with a common fileformat, he could make sure it would always work the same everywhere, without unneccesary conversions.
Oh stuff it, I've probably misunderstod something and this rant is all in vain.
(Update 2002-05: I have since learned that much of this is solved by using something called a mapped bytebuffer -- where you create a "view" of the buffer with a specified endianess --. Possibly in conjunction with FileChannels. I'm note sure how long these things have been around, but I think I wrote the above sometime around 1999 (I haven't used java much since around then). I have not studied the performance impact of this solution, but it sure beats doing the bitfiddling by hand.)The subject kind of says it all. I don't have the energy to expand on it.
I thought I'd try to collect some resources that are good to have in software development. All of this is not original work by me, and I won't wouch for it's correctness. You decide if it's worth using. Feel free to send over any material you might have that'd fit in here.
| PHP syntax highlighting scheme for GWD/GTE | Homebrew PHP scheme for my favourite win32 editor (With Classic Borland coloring) |
| dbRiktnummerOrter.txt | Contains a table of regional-phone prefixes and corresponding cities/towns. Swedish. |
| dbRiktnummerOrterSplit.txt | This version has had it's composed fields atomized further (ie no "Eskilstuna-Torshälla") |
| tblGenres.txt | The genre-list used by MP3 ID3 v1.1 tags. |
| tblISO639-2.txt | ISO639-2 specifies the three-letter countrycodes. |
| CRC32.java | A CRC-32 java class I wrote early on. Yes I know, there are CRC32-functions in the JDK already, but I wrote this as an exercise. Besides, I don't think you can change the polynomial in the JDK implementation. |