11 ms·
Terrible programming features from the past
- chiph 5y agoI'm guilty of using On Error Resume Next. It seemed like the easy way to deliver code that (mostly) worked.
- nsenifty 5y agoOn Error Resume Next was supposed to be used in conjunction with the global Err object that contained the recent most error. You would check Err.Code after each error prone operation for an error and handle it.
- amitport 5y agoDynamic scope https://en.m.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scope https://en.m.wikipedia.org/wiki/Scope_(computer_science)#Dyn...
- _ph_ 5y agoDynamic scope can be great, if used wisely. Of course, by default, you don't want dynamic scope for your variables. But to be able, as an exception, to declare dynamically scoped variables is exactly how you want to handle global values. Common Lisp handles this nicely.
- kazinator 5y agoCommon Lisp doesn't handle this at all in the way you describe. It does not have global lexical variables which you can opt-in to dynamic scope. It has only dynamically scoped globals. (Implementations may provide global lexicals as an extension.)
- skrebbel 5y agoI have fond memories of Aspect-Oriented Programming, which I feel should've been in this list. For those not in the know, AOP is basically the Intercal COME FROM statement (itself a pun on goto, ie it's a jump but in the opposite direction) (think that through a bit). Yes, that's a totally nuts idea, but it turns out that with a bit of effort you can formulate it in such a way that you can do conference talks about it and people nod and think "o wow nice I gotta tell the team". More concretely, AOP is usually a bit of compiler infrastructure that lets you inject code into other people's functions/methods etc and make arbitrary changes. It's nice for eg inserting logging code at the beginning of each method, with the method name and argument. You'd be able to eg define a query somewhere and say "for all methods with annotation X, inject code Y at the beginning of the method". But naturally, teams that adopted it always had this one team member who thought they knew better and started using it for injecting all kind of behavior-altering code in methods defined far, far away. When reading such a method's source, there was absolutely no way to tell that code was going to get injected. If the AOP crowd was well behaved there'd be an annotation/attribute/etc that would trigger the behavior, but that's not a requirement. I've seen people inject code that sanitized data, which was very surprising if said function didn't actually take user data and suddenly while debugging a string's content had changed and there was no indication whatsoever what had caused it.
- danidiaz 5y agoAspect-oriented programming is alive and well and living in the Spring Framework. While it can be misused (by making unclear what aspects are being applied, as you mention) it can be very useful and avoid a lot of boilerplate code and repeated logic.
- Phil-bitplex 5y agoThis is very similar to my biggest frustration with PubSub, or heavy event driven systems in general. The concept is so appealing, “Hey I’ll just fire this message off and whoever needs to know about it will do what they need”. It’s great to have that ability to focus on just the component or module you’re working on, but the lack of visibility on exactly what is about to happen, and what has happened, has caused many late nights of debugging and frustration. It’s just how you described “there’s absolutely no way to tell the code that was going to get injected” I’m guilty of contributing to this problem as well. Once you become familiar with the event system you’re working in, windows, DOM, whatever, you can make some pretty good assumptions about how other components are implemented. When you’re faced with a bug in code you don’t have access to, or a behaviour you don’t want, often the solution you’re left with is asking “okay, so what combination of events and timing do I need to force this component into the state I need?” For example I remember doing this with some third party grid controls. We really really wanted the TAB key to insert a new row at the end. We had to orchestrate exactly the right mix of events and method calls in the right order, with a few BeginInvokes to get the job done. I wish I had a solution to all of this and other frustrations. It’s all trade offs and a balancing act.
- fpoling 5y agoOn Error Resume Next is similar to NaN. In some situations the code can be much simpler if after a lengthy calculation one just test for an error result with no error checks in between. In modern languages that evolved into various forms of Maybe/Optional types with various syntax sugar like ?. or Haskel do notation.
- saithound 5y agoIt's disingenuous to suggest that "on error resume next" evolved into, or even influenced, Maybe/Optional types. The "on error" construct existed in QuickBasic, but it took a goto line number or label as its operand. "ON ERROR RESUME n" would give you a relative line, allowing you to jump n lines down. Since Visual Basic didn't care about line numbers, "on error" took a goto label instead. Visual Basic 3.0 introduced the "on error resume next" construct in 1993 so that the QuickBasic usage could be imitated. Meanwhile, already Haskell had Maybe/Option types and monadic notation in 1992.
- t7s 5y agoPHP Magic Quotes
- ElViajero 5y ago> On Error Resume Next takes an approach that’s the worst idea in many error situations Does this mean that this feature should not exist? Or that it may be misused? It seems just a kind of rough Java 'try-final'. If you know that an access to disk, e.g., may fail 'resume on next' just guaratees that the rest of code is executed. This would not be so wise in a language like C++ were you may have corrupted the stack. But, for basic it had its uses.
- Someone 5y agoIts problem is not that it exists, but that it’s a separate statement. In most languages, if you write try, you have to write catch or finally for your program to even start running. If you write on error resume next, you should revert that soon, but the language doesn’t prevent you from forgetting to do that. Neither, AFAIK, do typical editors. A good editor, IMO, would indent code inside a “on error resume next”, but I haven’t seen such editors. It does help that its scope ends at function/procedure return (I think), but of course, that means seemingly benign refactoring can change program behavior. It isn’t too bad when you write new code, but once you start maintaining a larger program, it can bite you.
- dkersten 5y agoHaving done some Visual Basic with that a long time ago, the problem with it is that its not fine grained and there's no easy way to know if something failed. For example, you have a large procedure with a division by zero somewhere in it, the code will just continue and you will never know, nor have a way to detect it. But often, if an error happens, the rest of the code will also be errors (or just be incorrect), so continuing to the next statement just masks the error, it doesn't do anything to handle it. I don't remember what happens in case of a file access failure: is there a way to detect that there was an error? (Other comment below suggests yes, but it sounds rather brittle to have to check the Err object after every statement) But if so, why not just check for errors without 'on error resume next'. At least with try-finally, you get to choose the scope of it, so you isolate the part where an error might occur that you wish to resume after.
- codebolt 5y ago
- neolog 5y ago`DoEvents` seems equivalent to the modern `await` feature.
- nathell 5y agoGCC also has dynamic gotos as a C extension, called „computed gotos”. See: https://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables https://eli.thegreenplace.net/2012/07/12/computed-goto-for-e... https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
- fiddlerwoaroof 5y agoFirst class functions are also very similar to dynamic gotos: https://dspace.mit.edu/handle/1721.1/5753 https://dspace.mit.edu/handle/1721.1/5753
- throwaway81523 5y agoThat is not much used directly by human C programmers. It's more for using C as a target language for another compiler, or in some cases as a fast dispatch in an interpreter. GNU Forth (gforth) uses it to dispatch between Forth words, for example.
- josephcsible 5y agoIt's kind of unfair to compare this to ALTER. Most of the time you're not using `goto *something;`, and when you're not, you know exactly where it's going to go. With COBOL's ALTER, it's as if every single goto were a computed goto, with the value of all of them being stored in global variables.
- Animats 5y agoALTER SELECT-PATH TO PROCEED TO PATH-2. That stores into the code. In the early days of computing, programs did not have a call stack and code was not usually re-entrant. No recursion. So, finding a place to store state was tough. This is still seen in some embedded code. It's all Von Neumann's fault. The program is stored in main memory, and he makes a big point that this means the program can modify itself. So early programming languages, operating systems, and CPUs tended to have support for that. Von Neumann didn't think of index registers. Array access involved code modification. It took a while for index registers to become a standard computer feature. The first one was in the Manchester Mark I, but they were, for too long, a "high end" feature. The IBM 650, IBM 1401, and the Intel 8080 lacked them.[1] Building in an extra adder cost money. [1] https://en.wikipedia.org/wiki/Index_register https://en.wikipedia.org/wiki/Index_register
- samatman 5y agoTo add to the history lesson, Herr Doktor Professor Djikstra's infamous "Go To Statement Considered Harmful" should perhaps have been titled "Call Stack Considered Very Useful". It's worth reading with this understanding, and of course, it is a must to follow through with Dr. Knuth's equally seminal "Structured Programming with go to Statements", in which Djikstra is briefly quoted to qualify and clarify his position on the matter.
- meepmorp 5y ago> To add to the history lesson, Herr Doktor Professor Djikstra Dijkstra was Dutch, not Deutsch.
- samatman 5y agoWell, yes. But I'm able to construct the German form from memory, and have found myself unable to produce a Dutch equivalent even from reference. When writing it, I imagined Meneer Djikstra rolling his eyes a bit. Which... fits.
- 5y ago
- bargle0 5y agoBourne shell, bash, etc. are all “on error resume next” by default. You have to `set -euo pipefail` explicitly.
- xiaq 5y agoIf you're interested in a shell that doesn't do "on error resume next", take a look at Elvish :) https://elv.sh/learn/tour.html#exceptions https://elv.sh/learn/tour.html#exceptions
- eikenberry 5y agoA bit pedantic, but to be clear `set -e` is the call to change the behavior from "on error resume next" to "on error exit". The `-u -o pipefail` are both other common error settings, but unrelated to that behavior.
- jeeyoungk 5y agoPipefail is actually relevant here; because the difference between `-e` and `-o pipefail` is whether “on error resume next” is supported for `cmd;cmd` versus `cmd|cmd`.
- jolmg 5y agoAlso languages without exceptions, like C.
- tompazourek 5y agoPowerShell also does this and is often used by the .NET folk that just expect the exceptions to work as usual. This causes so many issues...
- majkinetor 5y ago$ErrorAction = 'STOP' and you are done with it.
- dep_b 5y agoC64 BASIC allows for GOTO $LINE, but at least the dynamic GOTO’s look different than the static ones
- deleted 5y ago[deleted]
- zepto 5y agoOn error resume next was a hack from much earlier versions of basic where it was much more reasonable. I assume it was only still in VB6 for backwards compatibility.
- electroly 5y ago> The only possible reason you might use On Error Resume Next is if you have no error handling code at all The author (and pretty much everyone else who never used Visual Basic) misunderstands how it's used. The next line is expected to check the Err object to see if there was an error. It was never expected to be used for just ignoring errors; it's a way to switch from "exception style" to "error code style" error handling. It's true that it's a footgun because you can forget to check, but people misunderstand the intended usage.
- msbarnett 5y ago> The author (and pretty much everyone else who never used Visual Basic) misunderstands how it's used. The next line is expected to check the Err object to see if there was an error. It was never expected to be used for just ignoring errors; it's a way to switch from "exception style" to "error code style" error handling. I think this comes down to how you think about languages and features. Is a feature good if its intended use is that it be used carefully in limited circumstances and with careful error checking? Or is it a terrible feature if in practice, the largely low-skill userbase slapped it everywhere and anywhere they could with absolute abandon, because it made the confusing error messages go away? I think the author (and I) just fall in the latter camp. It doesn’t really matter that you weren’t “supposed” to use on error resume next except in limited scopes, and you were “supposed” to rigorously check the Err global afterwards. In practice, it was abused non-stop as a crutch by people who largely didn’t know what they were doing, and it made touching a VB6 codebase hell on earth. I’m not looking at the language in the abstract, but from the experience of having been handed maintainership of a few LOB VB6 apps early in my career. On error resume next’s consequences, how people actually used and abused it, are what matter, not whatever hypothetical nice way to use it existed in the docs and the maybe 1 in 50 VB programmers who approached the language with any knowledge or care. It was a godawful feature that vanishingly few VB programmers ever used correctly, and it made working with VB projects an absolute nightmare.
- setr 5y agoI recall reading that the primary purpose of the COBOL ALTER statement was actually for punch cards — you could fix a function by printing out the new function + alter statement, add it to the top of the card stack, and feed it through again — without having to reprint your program, or find the relevant cards to replace
- toolslive 5y agodata types with varying width per platform (C) How many bytes in a char,byte, int, .... ? (answer is: it depends )
- khoobid_shoma 5y agoActually, for a good reason, it depends! The standard specifies how to get useful information. There are also exact-width, minimum-width. fastest minimum-width, greatest-width,... integer types.
- pavlov 5y agoI don't really know what would have been a better solution at the time. In the early '70s, the native word size of computers varied in increments that feel unfamiliar today: DEC's line-up already contained 16-bit and 18-bit computers, and vendors were looking at 32-bit and 36-bit. C's solution was to define int as at least 16 bits long (but assumed to be the native word size), and char as at least 8 bits long (though it might be stored in a 9-bit half-word on an 18-bit machine, or even a full word on another type of machine).
- anoncake 5y ago> Read the rest of this story with a free account. Certainly not. Any mirrors?
- rwmj 5y agohttps://archive.is/HM8Kp https://archive.is/HM8Kp
- stordoff 5y agoJust opening it in Incognito Mode worked for me.
- deleted 5y ago[deleted]
- nyanpasu64 5y agoWith JS off, both regular and incognito mode didn't work. Turns out Medium now locks you out of articles if you don't enable JS. So much for HTML being a format for hypertext, rather than a delivery vector for arbitrary code execution.
- PopGreene 5y agoDuff's device. https://en.wikipedia.org/wiki/Duff%27s_device https://en.wikipedia.org/wiki/Duff%27s_device Please excuse me while I go barf.
- deleted 5y ago[deleted]
- qwerty456127 5y agoDoEvents is a great tool if your project is small and you use it consciously. Just make sure it won't invoke any I/O or heavy logic. This is easy when your app is small. And DoEvents let's you KISS and short. Not a single time in my life it caused a problem because I would always switch to BackgroundWorkers as soon as the app would grow more complex. On Error Resume Next wasn't anything really terrible either. You just enable it before a risky call so your program won't crash, do the call, disable it and validate the result of the call before using it. This way you just don't have to clutter your code with endless try-catch-finally clauses.
- codebolt 5y agoI always thought the classic synchronous message loop in Win32 was actually rather elegant if you took the time to understand the mechanics surrounding it. DoEvents is a bit crude but it serves a purpose in the context of VB6. Cant disagree about the error handling though, thats the absolute worst part of the language.
- tyingq 5y ago>DoEvents is a great tool if your project is small and you use it consciously. It exists in tcl/tk as "update" and/or "update idletasks".
- geon 5y ago> You just enable it before a risky call so your program won't crash, do the call, disable it and validate the result of the call before using it. This way you just don't have to clutter your code with endless try-catch-finally clauses. How is that in any way better than try/catch? It would be just as mush code, but without the syntax ensuring you disable it.
- qwerty456127 5y agoPerhaps you are right. But at least it's less nesting and I'm not sure special syntax to ensure you disable it is necessary - finding all occurrences of "On Error Resume Next" and matching "On Error Resume 0" statements is trivial. Both ways feel tidy than the other in their own way.
- mike_hock 5y ago> Today, some 60 years after the language was first created, the ALTER statement is considered obsolete and is scheduled for removal. Wat > scheduled for removal. Wat? > scheduled for removal. COBOL is still being developed?
- kmbfjr 5y agoWe all stand on the shoulders of those who came before us. Yes, they are bad ideas. But back when those old COBOL people were on the job, it is what they had in their tool kit. It is easy to make light of decades old ideas from a modern lamp. But wait, oh contemporary programmer, your day awaits to be mocked by someone who thinks they have the tiger by the tail.
- deleted 5y ago[deleted]
- only_as_i_fall 5y agoSounds like an interesting article but I will never create an account to read a free article. If I was king of HN Medium would be banned.
- O_H_E 5y agoFyi, you could just open it in an incognito tab or clear Medium's cookies
- laumars 5y agoThis is definitely a young coder because those features made some sense in the era they were created. In some cases they were life savers. On error resume next: This can be scoped. So I’m reality it’s was used in small sub routines where errors needed to be discarded. I’m not suggesting it’s a particularly great idiom but this comes from an era before try / catch blocks. DoEvents: This was vital back when your language runtime was event driven but also single threaded. It was a way of allowing the application not to lock up (and thus the user force closing it) when there was computationally heavy workload. These days you’d stick that workload in a new thread for async await but you’d have all the same problems of ensuring that you’d disabled UI elements first as the article describes with DoEvents. And actually DoEvents is rather more clever because you’re telling a single threaded application that was typically running on a single core/CPU system exactly where the safe points are to prioritise other processes. These days we have green threads, async/await and other concepts for lazy multitasking. But back when DoEvents was created there was no such thing and using real OS threads was very difficult (in fact it was officially unsupported in the languages that had DoEvents, though there were some unofficial jacks) so it was a real life saver in some scenarios.
- msbarnett 5y ago> On error resume next: This can be scoped. So I’m reality it’s was used in small sub routines where errors needed to be discarded. Your “in reality” sounds a lot nicer than mine. In my experience “On Error Resume Next” was slapped right at the top of every single lovecraftian horror that was a VB6 file, like a prayer to gods who had clearly abandoned humanity. Engineering inventory management? On error resume next. Departmental budget management? On error resume next. Telecom billing rectification? On error resume next. Was there some sane way to use it? Sure, probably there was a team, somewhere, somehow, using this language and making safe, sane, and well-reasoned decisions on how to best take advantage of its features while avoiding its sharpest edges. But the first thing I learned in this industry is that if you try to teach the average VB programmer to fish, they’ll have burnt down the village and strangled themselves in the line by lunchtime.
- unilynx 5y ago> It was a way of allowing the application not to lock up not just the application. with cooperative multitasking (eg windows 3.1) the whole computer would be unresponsive if you didn't give the event loop a chance to run.
- alexshendi 5y agoCan't read. Does it cover the following: * Computed GOTO * Arithmetic IF * Indentation based syntax * M-exprs * The Glasgow Haskell Compiler (I was going to write "The only thing that hurts more than the Glasgow razor gangs", but that's too cheesy).
- failwhaleshark 5y ago- Computed GOTO... ugh - Indentation-based syntax isn't a programming feature, it's a lexical/parsing style religion. In my religion, it looks much cleaner than extra punctuation, superfluous keywords, and the visual noise of curly braces. What's worse is special column flags. C F90 sucks C F95 still sucks C F18 probably still sucks
- alexshendi 5y agoYou know that you can use free form code layout and '!' comments since f90?
- exdsq 5y agoWhat's wrong with the GHC?
- failwhaleshark 5y ago- Forward declarations and header files. Two code files to manage for the price of one - Impure macros - Macros so pure you can't do token pasting and templating expressively
- yawaworht1978 5y agoI know a retired Cobol programmer, he would always say the alter statement was what causes him the most trouble.
- barry27 5y ago"Imagine if we responded in the same way to real-life accidents." On Error Resume Next is _exactly_ how real life situations should be responded to. Instead of On Error Share On Socials.
- ijidak 5y agoI'm happy to see goto did not make this list. Goto has some very valid use cases, and sometimes I want to throw a goto into my code to say, "Yes. I did that on purpose."
- klelatti 5y agoMany 1970/80s 8-bit basics allowed GOTO X rather than GOTO 10000. In Sinclair Basic though replacing the constant with the variable was potentially a significant efficiency win as the 10000 wasn't just stored as five bytes but rather 5 bytes plus six further bytes containing a floating point or integer representation of 10000. Using GOTO X thus saved ten bytes in this case - less the assignment to X. If there were lots of GOTOs (or more likely GOSUBs) to a particular point in the code this was worth doing. On a machine with less than 10k of free memory (16k Spectrum) this was a worthwhile saving and so was used quite a bit in practice.
- TheOtherHobbes 5y agoThe not so distant past: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equa...
- deviledeggs 5y agoSince people are mentioning current examples, putting message queues everywhere is a terrible modern pattern. Looks great on the surface. Ride through transient failures. Easier load balancing. Even out load spikes. But underneath, you're adding bufferbloat to your system. I've worked on systems where every service communicates with event queues. Debugging these things is hell. Problems with eventual consistency everywhere. Duplicate requests chilling in the queues where you can't see or get rid of them. Ordering issues. Bad messages/events clogging up queues. Upgrade nightmares whenever endpoints change. Adding a message queue between your services instead of doing things synchronously is a great way to sabotage a project.
- rjh29 5y agoSome of those can be resolved by using a distributed log (Kafka, Redis Streams) rather than a message queue. Not all of them though!
- andreskytt 5y agoDoEvents was not a programming thing, this is how Windows worked back in the day. Non-preemptive multitasking.
- pjmlp 5y agoHe forgot: - Implicit decay from arrays into pointers - No checked arithmetic by default - bounds checking placed on the shoulder of developers themselves - strings composed of a pointer and a null terminator, that might exist, with luck - implicit conversation from integer into nonexistent enumeration values
- bjoli 5y agoAnd the argument against your points usually makes no sense! Sure "performance". But these "features" should at the very least be on-by-default, with an opt-out for people who want to be able to shoot themselves in the foot.
- pjmlp 5y agoNot even sure "performance" is valid. Unisys keeps selling Burroughs as ClearPath MCP, not only because of legacy mainframes, rather it is an originally written platform in 1961 with system programming languages (ESPOL/NEWP) that take security seriously (the first set of languages with unsafe code blocks and instrisics instead of Assembly), so there are still customers around that are willing to pay for that extra security. https://www.unisys.com/offerings/clearpath-forward/clearpath-forward-products/clearpath-mcp-software https://www.unisys.com/offerings/clearpath-forward/clearpath... And then there is the whole experience from ALGOL compilers in production, "Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law." -- C.A.R Hoare on his Turing award speech in 1981.
- skocznymroczny 5y agoWhy is "On Error Resume Next" terrible, but not-nullable types are praised? With nullable types f.doStuff() will crash if f is null. With non-nullable types f?.doStuff() won't crash if f is null, the doStuff call will be silently dropped. Isn't that just like On Error Resume Next?
- throwaway8d8v8 5y agoOn Error Resume Next got me better grades. Circa 1998 ish I had to take a "Software Engineering" course in college. We had to use Visual Basic for our silly application, and only one of the 6 people in the group had any experience with VB at all. The project grading rules dictated that each program crash (which typically was some modal dialog with a system error and an OK button) during final demo was an entire letter-grade reduction (!!). Enter On Error Resume Next. No crashes, just keep going! Software doesn't exactly work properly/to specs? Whatever, that "costs less" points than crashing =)
- kazinator 5y ago> DoEvents() is a once-popular but very dangerous kludge for Windows applications that don’t want to deal with multithreading.* > The problem is that you never know exactly what DoEvents() is going to do. Other parts of your application may receive Windows messages (say, if the user clicks somewhere else), and they can start running their code in the space that you create when you call DoEvents(). This sounds bad, but it’s actually a lot of fun (if you like late-night debugging), because the result is just a little bit different on every computer! Oh, but if instead you introduce threads, you won't have any such problems, right? Maybe you're supposed to change the state of your program to "calculation running" so that when UI events are processed in the middle of DoEvents, this state is observed. If the calculation ran in a thread, you'd probably track that; the UI would know that the calculation is running and certain actions would be disabled or handled differently.