dBase: 1979-2026
delphinightmares.substack.com
delphinightmares.substack.com
After their first class, he brought home a fat dBASE IV manual. Since I was very interested in computer books, I read a good portion of it even though I had never touched dBASE in my life. I would daydream of all the little forms, queries, reports and labels I could make with dBASE. But I never got to touch dBASE in my life. We kids used to get LOGO lessons instead in school.
One day my father came back from his evening lesson mildly distressed about something he had learnt. He said they were being taught loops but in the loop there was an equation that seemed just plain wrong. It was:
i = i + 1
How could that be a valid equation? How could i ever equal i + 1? He mentioned that he had asked the teacher about it and from what I could gather, my teacher and my father were talking past each other. The teacher probably tried explaining that it was not an equation but an instruction instead, whereas my father continued to interpret i = i + 1 as an equation due to the algebra he was so familiar with. It sort of held up the class for a while.The teacher asked my father's name, perhaps so that he could talk to him separately later. But when he learnt my father's name, he realised that his son, me, went to the same school where he taught. So he told my father, 'When you get back home, ask your son about i = i + 1. He will explain it to you better than I am able to.'
And indeed I was able to explain it to him pretty well. I was eight or nine years old back then. And that was probably the first thing I taught my father!
When FORTRAN gained equality it went for .EQ. out of practicality and necessity. Many others followed suit but used the somewhat more pleasant == instead of .EQ..
But it didn’t have to happen that way. ALGOL decided to stick close to mathematical tradition:
= for equality
:= for assignment ("definition")
While x := x + 1 is still not clean mathematical notation, I think it wouldn’t have riled up OP’s father as much. If he’d squinted enough, he might even have been able to see little indices below the x’s there.
And now we have all 3 in Python (=, ==, and :=) which makes me sad.
if is_logged_in=True:
allow_access()
I've got... opinions on the way python separates statements and expressions, but there's some real benefits to it too. is_logged_in := True
or if is_logged_in := True:
I agree that this would require blurring the statement/expression distinction. You can still do that in a weird way, by disguising your assignment as an expression. This is valid: (is_logged_in := True)
The reason it was done that way because := was an afterthought, and making it the assignment operator would have introduced a breaking incompatibility. That lead to having 3 different symbols for 2 use cases (assignment and comparison).:= was bolted on after of course, and I think that was a mistake, but no one asked me, nor do I expect anyone to ;P
x := 4
was chosen because it looks similar to x ⇐ 4The Xerox keyboards had the support for ⇐, with its workstation OSes being all graphical based.
When Smalltalk grew beyond Xerox PARC walls, ⇐ turned into :=
You can see this in the original Xerox PARC documents and books for Smalltalk.
x is 5
x is x + 5
Set x to x + 5
Except that COBOL doesn’t allow an arithmetic expression there, so you have to write
COMPUTE X = X + 5.
instead. ;)X is 5
X is x + 5
I kid, of course, but "X is x + 5" brings Prolog to mind with all the unification and bidirectionality that implies.
Grammatically, this would not change X. "...GIVING X" would just return X. Since it's part of the same statement, it seems it should ignore the "ADD 5 TO X" part.
Now, if you'd like to place the result into X, I suggest "ADD 5 TO X" would suffice as the entire statement.
10 X = X + 1
20 Y = Y - X
If the computer is meant to solve two equations here, why not start with an example that has solutions??!Where this becomes extremely Rorsarch is the spectrum between "notation is absolutely critical: there is only one correct representation of programs in people's heads and we have to match that exactly" vs. "all program text is ultimately syntactic sugar and programmers will just adapt to whatever". History tells us that the C choice of = for assignment and == for equality testing won, but of course that's not a choice in a vacuum and it's tied up with a thousand other choices.
primes = 2 : sieve primes [3..]
sieve (p:ps) xs = let (h, t) = span (< p*p) xs in h ++ sieve ps (filter (\n -> rem n p > 0) t)
Here `primes` is a variable that refers to itself in its definition (called corecursion), and `sieve` is a recursive function.> ultimately DRAM is mutable
Ultimately the CPU executes machine code, but I don’t see you directly writing that. You’re cherry-picking to defend an indefensible position.
> It is believed that - alongside the BOLD source code (missing for more than 10+ years), the BDE and many original dBase source code was lost during the ill fated Borland + Corel merger (which was eventually called off).
This is confusing because the article is supposedly about dBase, and I have no idea why Bold is relevant. It's an example of where I feel the general negativity of the blog veers into random discussions.
To the best of my knowledge, the Bold source was not lost. In fact, Embarcadero open sourced it several years ago. The blog post has details: https://blogs.embarcadero.com/bold-for-delphi-is-open-source... I worked there at the time though I did not drive its open sourcing, but it is a positive move, and clearly contrasts the blog's statement. It appears actively maintained and updated these days. I would differentiate 'lost' from 'owned but not made available publicly'.
While one could debate which approach would be best for migrating such a project, an 'AI-led Big Bang Migration' would be insane.
However, AI would certainly be helpful for migration.
After inheriting a project where the source code CDROM went missing I can definitely see a use case for at least trying with the latest frontier models to rescue the logic because it took me a while to reverse that thing manually to fix a bug with radare2
> After inheriting a project where the source code CDROM went missing That sounds insane! Was it a VFP9 project?
Funny aside: I remember the first time my GE boss asked me for an invoice as it was the only way he could pay me. I had no idea what it should look like. So he sent me to the PM of one of the COBOL contractor teams who gave me a template that I copied. The PM eventually asked me to do some COBOL programming for them as well. Good times.
>By feeding legacy PRG (circa 1985) and logics to models like Claude, ChatGPT, developers can now instruct the AI to translate decades-old dBase PRG directly into memory-safe Rust, highly concurrent Go, or modern Dart/Flutter cross-platform applications.
And it alludes to this early on, but it doesn't show any examples.
In general LLMs seem to be very good at translating between programming languages and something like PRG uses very straightforward syntax and concepts. The first attempt by the LLM did a mostly one-to-one conversion using the console but i asked it to convert it to Windows Forms and the code looked fine for that too, using appropriate controls for the fields like text, combobox or datetime pickers (though it used fixed coordinates for the controls so i'm not sure if that looked fine).
FWIW, i didn't try to run the code (i'm on Linux and i do not even have anything related to C# on my PC nor a DB to work with :-P) and chances are there might be some subtle mistakes, but it looked like a decent starting point. IME, at least with local models, converting code between languages in a piecemeal fashion is trivial even with weird/less common languages (you may need to put some instructions to the LLM on a few edge cases though). And IMO that approach would be the right way to do it instead of dumping the entire codebase to it and hoping for the best :-P
https://github.com/infused/dbf/
I'm not sure what the article suggests - create a custom rust program that reads and writes to a given dbf file? Create a rust program that mirrors the PRG code, writing/reading data in a custom format?
There were some Turbo C and Turbo Pascal source code that read DBF files, but hardly anyone used them. Most stored data is in text files that can be read by any application.
Aside: I was such a fan of Foxbase that the very day Microsoft's acquisition was announced (circa ~1992), I invested $10,000 in Microsoft. I sold maybe 10 years later for $100,000. Stupid Stupid Stupid.
Great productivity tool, garbage collected, compiled, in the constrained environment of MS-DOS PCs.
The migration to Windows 3.1 took too much time, giving time to FoxPro, Access, Visual Basic and Delphi to establish themselves to the same programming communities.
Similar to other HNers, Clipper was also how I made my first attempts to working for others during high school.
IIRC, it needed one or two 360K floppies for a full install (a pirated copy; maybe the legal distribution was larger - at that time, all software was pirated). Compiling was fast (on a computer where you type dir and can read the filenames appearing on the screen faster than the computer can print them), but linking was slow, so everyone replaced MS Link with Borland’s TurboLink, which was an order of magnitude faster. It didn’t support overlays, but there were ways to work around that.
There was also documentation available in some third-party TSR app.
Later, another linker became popular: Blinker, which had a bunch of interesting features, such as loading overlays into EMS memory and providing various security functions to help protect your software. But by that time, the writing was already on the wall for DOS.
Funnily enough, many customers actually preferred DOS, since navigating with the keyboard was far faster than using a mouse, and Windows apps generally weren’t designed with keyboard navigation in mind.
Same in Iberian penisula regarding software acquisition, even during university, the same copy centers for books, also offered catalogs of which software we would like to have, or street baazars even, only in the 2000's the goverment (in Portugal) actually started hunting down those practices.
Strange it is not cited in the post.
The enterprise had to declare me as an apprentice for 'trade jobs', as it was against the law to give a regular salary to someone under 16.
I remember my first paycheck with deductions for retirement, which pissed me off quite a bit.
I think the main gist: you work not as app developer but as db developer, is something that is missing in some partial attempt like access and such.
BTW: Wanna join me or help?
The idea is to make things "relational" (with improvements) instead of fully "physical database tables" that is what tied you into a binary format.
With this, this binary format stop to begin opaque, and can be even be represented (tables and such) textually or by "standard" outputs like Msgpack.
So think that `data Customer` has decoupled the idioms, programatic interface to their specific storage. In rust terms, each `data` is `serde`, so you can change and move between how physically things are represented.
BTW this is how the relational idea was mean to be used.
Y'know what? It's probably true that niche needs filling again as long as it isn't the dBase file format. I had to deal with one system that blew the documented max file size for dBase III but for some bizarre reason, the original dBase III executable didn't care.
However, you couldn't load it with any of the ODBC drivers it would fail. Except for one obscure Sybase based driver I have forgotten the details of.
Just couldn't deal with it again I don't think.
So despite it being an incredibly old file format it's still used constantly in the GIS world and it's probably not going to go away because while it's not a good format, it does basically everything at to at least a mediocre level which can't be said for any of the newer formats that tend to do a few things great but other things terribly.
Like Geojson is great for interchange but you can't really do in place edits or even in place seeking from disk, shapefile can.
Sqlite allows great editing and seeking but you can't use that in a browser without doing something complicated like compiling the sqlite binary to js or wasm.
They could have still been the king of the hill now if it weren't for the suits who completely ruined it after Philippe Kahn left the scene.
I'm guessing dBase was itself built using Microsoft's compilers, so pulling in other code from the same compiler was plausible. Not a product choice re: the Turbo compilers, just a disjoint path dependency between two acquired product lines (Ashton-Tate's dBase, and Wizard C).
This is the reason that Clipper, a third-party dBase compiler, could only link against .OBJs from particular versions of Microsoft C. Clipper compiles to p-code whose interpreter is implemented in Microsoft C; "linking" a Clipper program is actually linking a Microsoft C program with a static array comprising the Clipper compiler's output. So you can mix in a .OBJ expecting that version of the Microsoft C runtime library. Not a .OBJ expecting the Turbo C++ runtime library.
I implemented reflection for the dBase language and was also part of trying to convert it to Visual C++ instead of using the Borland compiler. I was very green back then but it was interesting, my only time dealing with interpreters / compilers
Semi off-topic: The wikipedia article on Ed Esber is in dire need of a clean up https://en.wikipedia.org/wiki/Ed_Esber
Somehow I scored a (stripped down?) copy on multiple floppies that I couldn't even use, as an Amiga owner - but incredibly, this freebie came with a fantastic paper manual which I devoured.
Netware supported loading PE executables, but it lacked memory protection so developing for it was... fun.
The .dbf format was pretty straightforward, though.
The typical troubleshooting path with the b-tree system almost inevitably, and very quickly, led to a "rebuild the indexes" process which no one enjoyed.
The transactions on the SQL system pretty much eliminated that error path completely. Only actual on disk file corruption would lead to trouble. We could always (and did) post wrong data to the DB, but the DB did what it was told (right or wrong), but having the indexes lose sync with the as records was never a problem.
Its hard to describe how refreshing that was.
I'm sure there were b-tree systems with in built transaction systems to keep the base rows in sync with the indexes, but they were pretty late to the game and the SQL DBs started taking over.