Please do not delete this commented-out version
emacshorrors.com
emacshorrors.com
false ifTrue: [
"Some code to debug to help understand..."
].
In VisualWorks, you can double-click next to the 1st square bracket to select the code, then instantly execute it or debug it. The reason why it's not simply commented out, is that automated refactorings in the Smalltalk Refactoring Browser can then touch the commented-out code. (St RB used to be guaranteed to always execute strict refactorings and produce correct code.)Often such code can even use values from the current scope, so a separate debug session can be spawned to see what it "would have been like" then dismissed with no consequences. It's stuff like that which made Smalltalk an uber-environment back in the day.
(comment
(def some-state (create-state))
(some-fn [1 2 3])
(do-something some-state)
)
The compiler ignores the block, but in a REPL enabled editor, you can evaluate the forms to possibly view current state, or run functions that test behaviors or probe runtime state. #_(def some-state (create-state))
(some-fn [1 2 3])
(do-something some-state)) #_((def some-state (create-state))
(some-fn [1 2 3])
(do-something some-state))
oh, and you can't have "invalid" code in (comment), but in #_ you can.Didn't know about the difference in behaviour with regard to invalid code. Thanks for that.
EDIT: Leaving this here for context. I'd missed the fact that they weren't all enclosed in a single form to begin with. Parent's solution is correct in light of that.
Guile now has an elisp interpreter and guile itself has JIT capabilities as well as a number of other features elisp hackers have grumbled about over the years. It's been mostly one man's work but it has spanned years to get guile-elisp to where it is. The discussions about migrating to it have been somewhat interesting to read. You have a remarkably solid, cross platform, well tested product and they're very very cautious to harm that, even with big speed and feature improvements on the table. It's one of the few good examples of "maybe you want to think twice about fixing something that isn't broken." Then when/if they do fix it, I bet you'll be able to build it with the old elisp for 20 years, just in case something isn't quite right...
Surely the "D" in DVCS means that many thousands of copies of the project history would be available around the world?
On the other hand, I'm less confident about the conversion to bzr. And anyway the relevant question is not "would it have broken?" but "did people have reason to expect it would break?"
And on the third hand, a commit id could be referenced by author and timestamp, which would be invariant under (competent) repo conversions.
That said, referencing the commit by author and timestamp, instead of internal commit ID is the robust solution.
(Another company I worked for had commit log entries like "I like cheese" so perhaps this company wanted to erase history for a reason. Here in the 21st century version control systems finally get the respect they deserve, though I bet there's a sad number of shops that still don't use one).
Emacs is, as far as I know, the project with the oldest history stored in git. It contains the first commit from April 18th, 1985. https://www.openhub.net/p/emacs Here, look at the first few: http://git.savannah.gnu.org/cgit/emacs.git/log/?ofs=124080 Because that link is likely to go obsolete as more commits are added, here's the first commit: http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=ce5584...
That this commit even exists there is the result of 10 months of work by ESR, who perfected his RepoSurgeon tool on the Emacs repo, in order to cleanly pass over all the relevant commits and branches (and cleanup obsolete metadata from old version control systems). Here's one post about that work: http://esr.ibiblio.org/?p=5634
(as an aside, I think RepoSurgeon is a very interesting tool that operates on a git-fast-import operation stream, as invented by Keith Packard when he moved X.org to git. A git-fast-import stream is a wonderful VCS interoperable format)
Anyhow, my demonstrated point is: of any projects, I expect that Emacs is the least likely to ever lose history in a repository switch.
Okay, this is not the official repository but one I did for us fork developers. And as we learnt last year, the NetHack DevTeam itself has been using CVS only since 2002 and apparently before that, they were just mailing around patches.
But of course you can set the date for any commit, so it's just a matter of finding someone who wants to have an accurate commit history and a project that is old enough. Especially with GNU projects, there are probably several candidates that would have a history starting in the 80s.
I was appalled when I learnt that Linus threw away the complete commit history of Linux when he switched to git. That was a veritable WTF moment.
But at least some of the commit history would have been possible to incorporate into the new git repository.
I'm no expert on BitKeeper, there were probably more options to achieve that but it seems Linus didn't think it was needed.
git replace does work now somewhat better than git graft did but it shows that git was never meant to be used with multiple repositories.
Going by the commit message, Linus didn't see lots of harm by just cutting off the history:
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
https://github.com/torvalds/linux/commit/1da177eSeeing the original code will not necessarily explain old behavior. When you make a copy, how much are you planning to copy? To debug ancient code that calls 5 functions, you might need access to the histories of those 5 functions; and the histories of any functions they call, and heck maybe you only saw correct behavior on a certain OS or with certain input (none of which you may have access to). If you don't have all those histories, the "correct old code" you are looking at may even lie to you, as it suggests it is calling functions you think you are familiar with but those functions have changed in some important way.
After enough time passes — and at the rate this industry moves, time is short — the only thing that really matters is whether or not the program currently does what its current users require. And if it doesn't, you define what behavior you need it to have and find a way to fix it.
/* Parse base-64 output produced only by tar test versions
1.13.6 (1999-08-11) through 1.13.11 (1999-08-23).
Support for this will be withdrawn in future releases. */
I did some digging then and found at that it had been introduced in a commit that was (at that time) almost 10 years old, to the day.[2]1. http://git.savannah.gnu.org/cgit/tar.git/tree/src/list.c?id=...
2. http://git.savannah.gnu.org/cgit/tar.git/commit/?id=e4e62484...
Now that's a horror story, I hope I will never have to work with such code.
This magical equals haunts me to this day.
One fun issue on C64's BASIC was that you could force the interpreter to not tokenize lines, but they were printed verbatim on "list" - totally invisible to the user. Printing the line, then having BASIC parse the same output fixed the issue. Although the error was pretty obvious IIRC (some fatal interpreter error aborting operation).
I'm not sure what the TI machines did. There may have been some odd tokenization error in that line and by rewriting it, you kicked off the parser which made the bug go away.
But totally changing runtime behaviour with seemingly unrelated code changes is usually a good indicator that you've managed to trash the stack. A compiler that manages to trash its stack, now that has potential for some extreme levels of frustration.
'STRANGE: For some reason I have to add a comment here or FreeBasic 0.24-pre doesn't compile it
I've even seen what donatj said, of changing the source and then changing it back in order to remove an error. That sort of thing is generally a problem with the build system not producing reproducible results, such as not files not being recompiled when necessary. Since I have my own DSL that spits out FB code, and the FB code produced in different modules can have hidden conflicts, I've actually seen that one multiple times (my own fault).Really, the amazing thing is that just a few years later FB is actually pretty stable. I don't mean to put it down; I'm quite impressed with their work.
Here are two better alternative solutions:
* comments (in natural language not code) that describe what the code should do
* test cases: to dictate what code should do and prove it does do it* Comments referencing the original code by date / version / commit id. Date and version are relevant because the comment might not get updated if there is ever another VCS migration.
In this case, since he apparently doesn't feel that he has that perfect understanding, he left the original code there, so when someone says "Hey! I counted on behavior XXX, this change broke my workflow!".
And any change no matter how trivial or "correct" always breaks someone's workflow.
The actual problem at hand was rewriting that function in a way that doesn't break the uncounted thousands of usages in the wild, which depend on the self-described "complex and likely to have subtle bugs" original implementation.
That is really toxic language. It's important to call out bad practices where they exist. Not having good comments and test cases for intended behavior is a bad practice. Yes, in the real world, plenty of code gets shipped without adhering to these practices, but it's really unfortunate to see someone talked down on for showing where good practices could have prevented the current circumstances. AFAIK, neither of you have personally written those lines of code, so why is ego getting in the way here?
Yes, the language isn't the most ... diplomatic ... but it is also frank & honestly expresses one difference a decade of experience makes for most professional programmers.
Excellent insight!
I find those kinds of comments insufferable as well, but I'll assume you actually wanted an answer and not just an excuse to chastise someone:
It's because those of us who have learned we don't know everything are annoyed by people who still act like they do know everything. It hurts because we're embarrassed by remembering our younger selves.
This is a beautiful way of explaining this. And so true!
I can't imagine why you would have written,
> Chocolate is toxic to dogs - it doesn't mean that chocolate is dangerous in all circumstances.
if you didn't think that.
Or: Sure. How about murderers? They are frequently described as inhuman, barbaric, etc. Was that really the point you were trying to make, or is there something else you are getting at?
That doesn't put ostracizing young programmers in the plus column.
I responded. Explain yourself more precisely if you want me to consider your point...
For sure. I'm an example. And I have a reason for this.
I remember myself from some ten years ago and I remember how far from reality my thinking was. I was largely self-taught, but I read many, many books and even wrote quite a bit of working code. I wish someone told me how naive I was, how mistaken in many areas. Instead, I went on to work - having quite a good luck and joining a very capable, professional team - and was in for the most depressing half a year in my life. All my teammates helped, and gradually I started seeing things in context and learned to appreciate all the accidental complexity and real-life requirements. However, this still was a terrifying experience for me and I'd be much better off, I think, had someone told me, without trying to be unnecessarily polite, how stupid and childish I was BEFORE I went and got bitch-slapped hard (repeatedly) by reality.
So yeah, I have no motivation to do this myself, because young programmers are indeed insufferable, but I cheer for everyone who tries to destroy the false, unfounded confidence of "young programmers". I strongly believe it will be good for these younglings in the long run.
It's honest communication, something that is becoming increasingly rare in this world of language policing. It's good to be nice to other people, but History as shown us time and again that freedom of speech is a very precious and important thing.
> Not having good comments and test cases for intended behavior is a bad practice.
This might be true, but nobody really knows for sure. There isn't a single development methodology that has been shown by rigorous experiments to be any better than anything else. In this case you have experienced developers doing what they think is best. Emacs is a very old and widely used project. There are very few software projects at that level of sustained impact (which is what actually matters in the end). Some humility might be wise.
It's political correctness gone mad!
/s
I suppose. But second guessing the development of GNU Emacs in 1984 (let's be clear: a program on the short list of the most successful bits of software ever written in the history of computing) might be a bad place to start if you're trying to avoid embarassing yourself.
RMS was writing this, alone, on a VAX most likely, or maybe a Sun 2 if he was really lucky. What hardware do you expect he would have dedicated to that putative "test suite" even if he had time to write it?
Kids today.
A really simple way to solve this would be to move the simplified algorithm to a test suite which iterated over some important edge conditions and validated that the simplified algorithm and the refactored code agreed. That would preserve the simplified code, but in a much more useful form where automated testing could be done against it.
My experience has been the reverse: lots of ultimately pointless tests add nothing to a given codebase but maintenance costs and developer frustration.
The most successful projects I've worked on used (completely automated, no code getting pushed to staging unless the CI server says it passes) tests sparingly.
I can't fathom how anyone thinks that documenting the algorithm is better than running the algorithm. The only possible explanation that occurs to me is sociological and that when someone eventually breaks the code which was only documented, you can heap scorn on those who allowed it to be broken because they weren't as smart as you are to be able to see that edge case in hindsight.
Which I guess is 'better'. I'd prefer to have a test that fails. When code breaks an edge case that nobody thought of, I'd add that edge case to the test suite. It will never be perfect, but it will work at least some of the time.
And assuming that test suites must be perfect and complete to be useful is also incredibly naive and a sign of an immature and fairly novice developer. Test suites are always imperfect, you must always guard against them and not assume they do everything for you, and yet you need to take the time to build them and maintain them since they make your code quality better when they do catch edge conditions where you weren't smart enough to see your own bugs you were introducing.
I guess some programmers are just smart enough to never commit buggy code though and don't need them...
You said it.
Don't write comments about what the code should do. If you have to write something, comment on the domain/context, not the code.
The old version of this code is under source-control <here>. The code is very complex and likely to have subtle bugs. If bugs _are_ found, it might be of interest to look at the old code and see what did it do in the relevant situation.
Even the comment in question admits: "it's true that it will be accessible from the repository".
Only then it goes on to say "but a few years from deletion, people will forget it is there" - well, then just leave a comment reminding them about it.
I see no plausible reason for keeping dead, commented out code in the codebase when you've got VCS.
It is somewhat surprising that this would last 30 years though. In our huge codebase, barely any lines have survived 8 years. Even less so the comments.
This argument can be used to ban anything. Where do you draw the line?
Jokes aside, one possible line is "it should make sense after a while of considering alternative solutions".
By exercising judgment. Thank God that's still required, else we'd be out of a job ;)
Their argument is "it explains the configuration". My argument is that it's more important to be able to quickly see what configuration is actually applied (which usually fits in a terminal window without scrolling) then it is to redundantly store help-text on the server (which also makes it hard to read what is enabled).
What the current configuration _means_, however, is a different matter. I have worked on systems where the explanatory comments are only accessible in a different system. One more extra hurdle, whether they are helpful or not...
Which means I need the config files.
I'm not against ALL comments - i.e. if something has a non-obvious external issue, that's worth noting. But people argue that the very verbose default comments, for example, should be left in - that's pointless, and potentially hazardous.
:view
:g/^\s*#/d
(this sets vim into read-only mode and then deletes all comment lines, assuming # for comments).comments like "does this" are telling you the name of the function that the following code should be in.
... so unless your scripts/configuration data are written in a very esoteric language or format i'm inclined to agree with your point very strongly.
Unfortunately, many distributions ship configuration files in /etc with a pile of commented-out defaults and documentation, on the theory that doing so makes them easy to edit.
Personally, I prefer the current approach of not shipping a file in /etc at all, shipping the defaults in /usr if anywhere, and thus reducing the file in /etc to actual configuration.
This is one of the things revision control is for, after all. If you are really worried your tools aren't up to the task of finding the old versions, you leave a one line comment with tag and rev.
It's true in theory all your old code is stored in vcs but it's such a bear to actually go look at it.
Gives all the commits with changes inside the function, shows each one side-by-side.
http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=488759...
It must have been done for a reason right, emacs is incredibly old in tech years and solid as a rock.
Funny: Tried to find the comment commenting it out. I found it. #IF 0. Wow.
#if 0 is also a convenient way to flip bits of test/debug code on and off.
#if 0 <...> #else <...> #endif
Is a pretty standard way to switch between new/old code while refactoring to check if behavior/output matches. Just change 0 to 1 to switch between "versions".Quite a lot of the #ifdef damage is to deal with VMS.
it can still be solid as a rock and be needlessly difficult to read, written in a poor style. they aren't mutually exclusive things, despite what many may preach.
For example, those naming practices were pretty essential when working with 80-character monitors.
And all those ifdefs were required for dealing with DEC minicomputers and (later) microcomputers. A minicomputer, if you didn't know, was something that in terms of power and cost existed between a mainframe and microcomputer (i.e., a PC).
Breaking out the code into different functions by platform (segmented by ifdef statements) would create unnecessary code bloat unless the implementations differed significantly. And believe it or not, this was much more readable (with the technology of the time) than calling separate functions within a master function, requiring referring to each function separately. Of course, ifdefs for different platforms are still required, and are often used in a similar way today.
I guess what I'm trying to say here is that there were very practical and pragmatic reasons code used to look like this, and that things much more obscure and (to modern eyes) hard to read were written by very smart people who knew exactly what they were doing.
I say that - may be I led a charmed life. Sigh.
Saying it is indefensible to manipulate strings in C is coming pretty close to saying it is indefensible to use C (and after they went to all that work to put together C11!). For most programmers, perhaps. But it still has its uses, and as of C11 safer standard string manipulation functions, as well. A competent, security-minded C programmer can write perfectly safe string handling code in modern C.
Still, it wouldn't be my first choice. A Jedi may use a lightsaber effectively, but a novice will probably just end up cutting off his leg.
When I come across code I don't understand I base my assumptions on the belief that the original programmer was smart, knew what they were doing, and had specific reasons writing the code as such.
Here is the same code in JOE (which has no VMS support and which treats foo/../bar and bar as different files - the original emacs code was written before symlinks!). JOE has a variable length string library, so you see 'vsncpy' instead of the alloca / strcpy / strcat / make_string.
http://sourceforge.net/p/joe-editor/mercurial/ci/default/tre...
Edit: Holy Cow! The new version in emacs is much more involved: https://github.com/emacs-mirror/emacs/blob/master/src/fileio...
"For technical reasons, this function can return correct but non-intuitive results for the root directory; for instance, (expand-file-name ".." "/") returns "/.."... " :-)
expand-file-name doesn't do that; (expand-file-name "/foo//bar") produces "/foo/bar", just like any other pathname canonicalization.
I can't help but wonder why emacs doesn't write that function in lisp, rather than C.
Maybe the code predates the lisp interpreter.
I mean, let's look at it like this: does the author of the removed code have a vote in what should happen, through the comment? If it's so important, why was it removed?
How do we even know that the new code did something wrong? We do not know that in relation to the old function; we know that in relation to some modern criterion. Maybe it completely bombs (irrelevant that the old code didn't bomb, or whether or not it did), or that returns some result someone doesn't like (without regard for what the old code did), or that violates some documentation.
We can decide today what the code should do, and fix it, or its specification or both.
I'm not saying that the above solution should have been deployed at the time, but perhaps it could be moved in that direction now that we have these techniques and tools to hand.
Could such a solution work well here? Perhaps, it would be even more useful, as tests would be likely to fail if the optimisation was bad, rather than just assisting with debugging after the fact.
There have, in fact, been 5 source code repository switches in LibreOffice over the last 30 years. [3] It started with some sort of proprietary version from 1988 to 2000 so there is no history at all from this period (which I think is a great loss...), from 2000 to 2009 they used CVS, then from 2008 to 2009 they used SVN, then from 2009 to 2011 it was Mercurial, then from 2011 to 2014 it was back to SVN, and LibreOffice started using git from the very start.
One of the worst practices that the OpenOffice.org team had was to get a whole bunch of work, bundle it up into a single commit and then note that there were multiple fixes in the commit. This makes it nigh-on impossible to untangle what fixed what. They apparently branched in SVN, then took the branch and merged it, but then blatted the original branch so now this is all lost in history.
And if you've ever read some of the most crufty parts of LibreOffice (cough VCL cough) then you'd understand that actually reading good commits is really very important for moments you think "what on EARTH is that code doing?!?"...
1. https://bugs.documentfoundation.org/show_bug.cgi?id=96826
2. http://randomtechnicalstuff.blogspot.com.au/2016/01/possible...
3. https://archive.fosdem.org/2014/schedule/event/exploring_ope...
And when reading somebody else's code, I tend to appreciate if the code carries its history with it, at least to a degree. What I really do not like, though, is when there is a piece of commented-out code with no explanation of why it's there in the first place or why it was commented out.
I've had codebases with references to bug IDs... from 3 bug trackers ago.
Just add a comment saying that this is a rewrite of the old part the code and document any intended functional differences. You can then search through the history for the first appearance of that specific comment. With git this is done with the pickaxe command.
If you have any comments in your code at all, you could make the same argument about "not knowing how to use your version control system" as everything could be in commit logs.
And please define "team-friendly", it is absurd to suggest that the git cli makes anything friendly.
Is this how you develop?
1. Comment out old code. Make a note of why this was removed (and maybe the date).
2. Add new code.
3. Commit.
Its the fastest way to get a bunch of comments in your code(as well as code) that is probably meaningless if not actively bad for you to store in your brain.
1. Write comment about code, and commit it.
2. Delete comment about code, and commit the removal.
I mean hey - your team mates should be able to use a VCS right?
Facetious workflows miss the point, judgment can be used to determine what should be commented out vs not.
I strongly prefer source code that is well documented, not at some point in the past, but right there at HEAD/master/main/tip/whatever
It seems to me (and I may be wrong) that it would make more sense to either turn the reference implementation into a spec document (and keep that next to the code) or to dub that code the "canonical reference implementation" instead of referencing some ancient version of Emacs.
By referencing the ancient version of Emacs (and the subsequent change to the new code), the comment comes across as an anachronism. It was (seemingly) left there in case there were compatibility issues while moving to the new code. This seems out of place now because if compatibility issues haven't come up in 30+ years, then I doubt that they will now (or that there is much code relying on edge-case quirks from such ancient versions of Emacs).
At what point does the current implementation (and any quirks that deviate from that ancient version) become the reference implementation? In another 30 years?
No, it does not. Emacs has gone through 4 version control systems, I can't imagine how they'd refer to it in a comment. As someone who's been through several, I guarantee you that git is not the final frontier of VCS.
Also - if you intend the comment to communicate to your team (as this commit does.. did you read it?), then your other comments also make little logical sense.
Read the linked article more carefully.
It's an example of how, sometimes, it's better to keep comments in the code than relying on source control to preserve them.
These situations are rare, but they happen.
People who say "Commented code should always be deleted, period" need to be a bit more open minded about the constraints in which we operate in the real world.
Of course people will go to great lengths to justify cutting corners, shortcuts, messiness etc. it's always called for by exceptional circumstances :) I just hope my doctor isn't open-minded about washing his hands...
Likewise, naming variables, functions, classes, and continuously typing out the same name over and over again means that your language and IDE is not rich enough to contain pronouns, making you have to type tediously instead of something even sightly more natural.
Why don't we improve languages so that they have pronouns for the stuff you're doing right there? Why don't comments get linked to line numbers in some external layer? And why would anyone commit commnented-out code to a repository?
The only answer to all of the above is that we are living in 2015 and not some future year. you work with what you have.
Interestingly, we do sort of have that - in most CAS interfaces "Ans" can be used to refer to the last calculated value. A lot of programming REPLs can do this sort of thing too.
Another example might perhaps be Bash's $1, $2, $3 etc for positional arguments.
However, commenting some code out also doesn't mean it won't rot. Methods/procedures around it will be refactored, variables renamed - in long time perspective, in a different landscape it can become incomprehensible and useless anyway.
Just because some abstraction (version control) can be a bit leaky and one shouldn't rely on it absolutely, doesn't justify succumbing to some other illusion.
Commenting code out is not equal to hibernation and it doesn't make it immune to flowing time. You uncomment it one day, you discover it stinks to heaven high - especially if it was complex from the start - and isn't informative at all.
"But that's not the case here!" - well, guess what: version control failing to do what it's supposed to also isn't the case here, if you can still access commits from 1986, as someone pointed out: http://git.savannah.gnu.org/cgit/emacs.git/log/?ofs=124080
"VIM is the worst written software in existence today. So we deleted a ton of it and rewrote it as neovim"... Waiting on neoemacs.
NeoVIM is mainly about the personal cost of contributing to VIM, protection of ancient platforms, etc.
Emacs doesn't have these problems for a contributor.
You mean Guile Emacs: http://www.emacswiki.org/emacs/GuileEmacs
I am not sure how far along they are, but I like the idea, because Lua is a really sweet language for this kind of task.
I personally hate when commented out code are checked in to source, but put in a situation where the "right" thing increases the likelihood human error, I'll pick the "wrong" way every time.
/* Here's the deal...Check out what this used to
look like at http://example.com. */I think that they should've put this right there in the comment, really.
Emacs is an old codebase. It predates modern repositories, or close to it, and it certainly predates the repository it currently uses.
And for that matter, does burguggle-git-svn keep SVN revisions traceable? Or are we assuming git is the pinnacle of software revision control and emacs would never ever change again.
Don't remove this code: it's true that it will be accessible from the repository, but a few years from deletion, people will forget it is there.Per the article, the comment in the comment was added in 2001 when the comment was recreated after someone else deleted it.
The original commented out version predates the first public release back in the mid-80s.
From the way people carry on when they see commented-out code like this, you'd get the impression that people actually paid attention to what was in comments! But if only that were so...
Usually leaving commented-out code in source control is bad, but in this case it's good.
[0] http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=488759...
emacs. an anachronism made of other anachronisms...