H. S. Teoh 
Posted in reply to harakim
| On Tue, Jul 25, 2023 at 07:28:46AM +0000, harakim via Digitalmars-d wrote:
> On Monday, 24 July 2023 at 07:22:57 UTC, Paolo Invernizzi wrote:
[...]
> > You know, I'm in the "deprecate and clean-up the language" camp since forever ...
>
> I am glad there is a deprecate and clean-up the language camp and it's gotten D to where it is today. I like to have improvements like that, but for about 7 years I have been in the stabilize the language camp and I'd like to explain why.
>
> I have java code from 2006 that still compiles today. I have tens of thousands of lines of c/assembly from 1998 that compiles today with two errors and I would bet there's a flag to make it work if I didn't want to change it. In college (about 15 years ago) I helped someone with some code for their PHD dissertation. It was Fortran 57 code copied out of a textbook and it also compiled without issue. IMO, this is the norm for a project.
>
> In contrast, I don't know that I have ever come back to an old D project and had it compile. Just the other day, I went to compile some code I wrote with dmd 2.100 with a 2.104 compiler and it would not compile. Sure, it's an easy fix, but that's not always the case and I am tired of tools that nickel-and-dime me.
I'm actually in both camps, if that even makes sense. :-D
One of the main reasons I liked D so much is that it got rid of a lot of baggage in C/C++ that it inherits from, resulting in a much cleaner language with fewer dark corners and gotchas. Over time, however, it has started accumulating its own cruft and share of dark corners. Sometimes I wish those corners could be straightened out, but each time my hopes are dashed by the spectre of "we don't want to break user code".
Ironically, at the same time user code continues to break, including my own projects, and that's also frustrating. I remember several D projects where, coming back to it after a couple of years hoping to make a quick 5-minute fix for a small issue, I end up spending hours or even days to update it because something got deprecated, or plain broke, due to some language changes. There was one project that I couldn't even compile for *months* before my loud complaining pushed some kind soul to fix it. So in that sense I'm also in the "please don't break my existing code" camp.
These two camps seem fundamentally incompatible with each other, but I've been thinking there must be a way to have the best of both worlds. I've suggested this before, but versioning source code seems to be a potential approach. Each source file should have a version declaration to declare which version of the language/compiler it's based on, and when the compiler sees this, it enables "compatibility mode", effectively compile the file as much as possible with the old semantics of the language. Breaking changes are suppressed so that it behaves as if it was an older version of the language. Optionally when an old feature is used a warning is issued, but compilation should not abort because of that -- it should still compile and work as before. Give the user the option of using the old semantics until he's ready to upgrade it.
Of course, some changes are fundamentally incompatible with older versions of the language; in those cases we'd have to issue an error. In the ideal world, this shouldn't happen. New code added to an old project can declare a newer version and use new features, but the old code will continue to use the older version until the programmer manually changes the version declaration. This shouldn't matter, because if new code X uses a new feature that causes a compile error due to bad interaction with old module M, it wouldn't have been checked in, in the first place. If it ever compiled, that means X must be compatible with M in spite of the version difference, so the compiler should just continue to compile it as before. If X becomes incompatible with M and the author updates M to be compatible, then so much the better. But if not, things should still work as before.
Libraries should also have access to the declared version of the caller, so that when the library API changes, the old API can be kept present to keep existing callers compilable; user code can optionally declare a version to use the latest and greatest API instead, and update his code to be compatible. As long as the old version is in effect, there should be no API breakages.
Essentially, what I'm proposing is in effect the equivalent of having a virtual dub package whose versions reflect the language version, and different modules will depend on different versions. If there's a way to resolve the dependencies, then the code should compile. If not, it won't compile, and wouldn't have compiled in the first place, so users should have already noticed this and did something about it. But a project that used to compile should continue to do so no matter what.
T
--
It's amazing how careful choice of punctuation can leave you hanging:
|