Who said "Anybody can learn to code" ?
Someone who needs software and wants someone else to write it?
Danke,
Who said "Anybody can learn to code" ?
Someone who needs software and wants someone else to write it?
Danke,
ANYONE can learn to code. Coding is a largely mechanical skill. Do this to get that.
Knowing which THIS to do is the issue.
What's the difference between:
for (i = 0; i < MAXI; i++) for (j = 0; j < MAXJ; j++) array[i][j]=17
and
for (j = 0; j < MAXJ; j++) for (i = 0; i < MAXI; i++) array[i][j]=17
(this is CompSci 101 material)
And, memset( &array[0][0], 17, MAXI*MAXJ )
And, more importantly, why/when would you use each approach? When would each *fail* -- silently or otherwise??
Coders are technicians. They don't understand the "science" that goes into the *design* of algorithms. Never formally looked at concurrency design methodologies, race/hazzard avoidance, non-locking protocols, etc.
A coder would *pick* one of the above -- likely without even considering that there are alternatives (or the criteria for successfully choosing between them).
I've seen production code where three copies of a variable were stored -- for redundancy. Without realizing what a collosal waste of bits that was.
Or, loops that read (and discarded) bytes from a file one at a time -- just to determine the file's size.
D'uh...
Give them a datasheet (dataBOOK, nowadays) and tell them to build a BSP and they'll be as a deer in headlights: "Where (how!) do I start?"
"Can't we use a PC (or some other "module") for that?"
Transposing an array is a better example for these purpose.
Someone would invariably bring our Starlink VAX to its knees by doing it the naive way in a noddy style loop. It was annoying because everybody was handling very large (for the time) images and highly optimised transpose a rectangular array subroutines were in the library.
for (i = 0; i < MAXI; i++) for (j = 0; j < MAXJ; j++) array[i][j] = array[j][i]
Generates an insane number of page faults once MAXI*MAXJ > pagesize.
It even does in Fortran which knows how to do large multi dimensional arrays properly in contiguous memory (unlike C).
I think it varies a lot with institution. The deskilling of coding software has resulted in an underclass of semi-literate journeyman coders who have no real mathematical knowledge to underpin what they do.
In my day it was pretty common to test out Knuth's algorithms - we even found a bug in one of the prime testing codes. Though not in time to get a $2^N reward for finding it. Did get a nice postcard from him though. I didn't do computer science but sneaked along to some of their lectures when they didn't conflict with my actual subject.
The scariest thing I see all too often with clueless C/C++ coders is the method of getting it to compile by the random application of casts. Such code almost never does what the author expects or intended.
Modern compilers and runtimes have got a lot better at warning idiots that they have uninitialised variables and/or unreachable code. It should lead to better software in the future (or so I hope).
Perhaps the future is deep AI based where the computer prompts the domain expert to say what they want done down each of the less exploered branches in the tree. It has been my experience that it is invariably the obscure rare failure of something critical paths that may go untested (until that failure actually happens).
But this is *obvious*! And, something that is frequently done (though the assignment may be some expression instead of a constant and other actions may exist in the loops).
What happens when MAX{I,J} is MAXINT? Will you (eventually) "lift" a piece of this code from an app where it *works* and misapply it to another where it *won't*? The *code* is correct in each of these cases...
Cache misses are a more common issue as many folks don't use a PMMU (in an embedded product) -- yet caches abound! "It's just code" -- as if all implementations are equivalent.
[The same sorts of folks likely don't understand cancellation]Wait until embedded systems start having to deal with runtime thrashing :>
(The fact that the cache is being abused is largely hidden from the coder because he doesn't understand HOW performance is defined)
There has been a shift towards "teaching what employers seek" -- creating employees with limited, short-term skillsets to address TODAY's need(s) at the expense of knowing about those things that will be available, tomorrow.
Increasingly, processor architectures are becoming more "minicomputer-like" than microcomputer. Yet, the folks using them are oblivious to the mechanisms available to the practitioner -- because they just see a "module with BSP/runtime", often created by a company with similarly limited focus.
"Why implement a VMM system -- there's no disk!"
(Hint: that's not the only use!)
We spent a lot of time on theory because most of the equipment was ... "unique". A different language, OS, hardware, focus, etc. in each class. A "coder" would quickly be lost: in this class, you'll be using LISP; this other, Algol; another, Pascal; C in a fourth; etc. All in the course of a *day*. The coder largely just thinks about syntax and not the "why" behind language features.
For us, the *language* was insignificant -- the focus was on the algorithms and the mechanisms that a particular language made possible or the supporting hardware (e.g., B5000). E.g., lists are inconvenient mechanisms in most procedural languages yet delightfully effective in others.
"Lambda calculus? Which *machine* does THAT run on??" "DFA? What class of problems do *they* solve?" "Recursion? How do I *know* I won't overrun the stack?" "What should the objects in this application be?" "How is object-BASED different from object-ORIENTED?" "What does a language need to support for the latter?"
Exactly. "How do I silence this compiler's WARNINGS?" (Hint: they are called warnings FOR A REASON!)
Some languages make it harder to "appease" the compiler with things that are "wrong". E.g., Limbo doesn't support pointers, is much more strongly typed, etc. Of course, it relies on GC to give the coder that "freedom". Does the coder *know* what that will cost him in any particular application? Or, is it a case of "overprovision to be on the safe side" -- much like "make everything HRT cuz SRT is *so* much harder!"
I'm not sure that follows. The advent of faster tools seems not to have led to smarter coders but, rather, more opportunities to GUESS what the problem MIGHT be. When it took four-hours to "turn the crank" (i.e., two builds per day), you were REALLY certain about the fixes you would try cuz you didn't have much time to "play". Add to that, having to SHARE access to tools and you learned to be very methodical about getting SOMETHING from each build.
The problem that has to be solved is imagining the entire extent of the application. I would routinely interview clients to define the extent of a job: "What do you want to happen in THIS case?" Folks often don't know. Do we let an AI *suggest* possible constraints? Will everything just "throw an error" instead of doing something useful?
Our microwave oven lets you type in a time interval for the maggie.
0-59 makes sense as "number of seconds". What about "60+"? Should those values throw errors (59 seconds is maximum in 1:00)? If we let 60 be a valid entry, what about 70? 80? 90? 100?? In the latter case, how do we indicate 1:00 -- add a semicolon or other delimiter?We're already seeing the shifting of focus in coders as they "rely" on more bloated systems on which to build their applications. Amusing that a 50 year old OS is the basis for many apps, today. Really? You think that's the way to solve every problem? Most engineers learn about the limitations of implementations and seek/try new ideas -- instead of being wed to an obsolescent one.
And, that -- despite MILLIONS of manhours -- it's still loaded with bugs! (because the developers are enamored with themselves and haven't learned to "shoot the engineer" -- nor does the idea even seem to be in their psyche!)
"Everything should be as simple as it can be, but not simpler"
Instead of thinking about what they *need*, they think about what they can do with what they THINK they *have* -- as if it can't possibly have bugs despite the extra complexity/bloat that they're employing. Imagine having a box full of discretes and felt obligated to find a use for them in your hardware design (WTF???)
That's what happens when you throw coders at a project. And, let inertia govern your design choices! :<
OTOH, when you let software engineers design a system, they have a deeper well to draw on for experience as well as exposure to broader ideas that may -- only now -- be becoming practical "in the small".
E.g., MULTICS was designed for infinite up-time -- you replace components WHILE the system is still running. Just like an electric utility replaces equipment while folks are using it! Why all this "reboot required" nonsense? Why can't I replace a library while applications are being launched and binding (or bound!) to it? Ans: because the idea is anathema to you because you've a coder's mentality ("That's just how it's done...")
Raspberry Pi Pico runs code out of a serial flash chip with 16 KB of code cache, shared between two CPUs. That can get interesting.
Well, I used to do entire systems running the code out of that much eprom.
Actually, I had a successful CAMAC module with a 6802 CPU and a 16 kbit eprom, 2 Kbyte of code, with room to spare. No FPGA.
The modern equivalent is a $100 dual-core 600 MHz ZYNQ with gigabytes of SD card running Linux, at 40x the development cost.
Different languages use different multidimensional array layouts. With Fortran it makes sense to use the innermost loop to access the _first_ index, while in C the "virtual memory friendly" is to use the innermost loop for the _last_ index.
An application originally written in Fortran will behave really badly if simply converted to C to avoid compiler syntax errors :-).
This is a bad example, since in transposing an array, either the input or output array is processed optimally, but not both. If input is stored optimally, the output is scattered all over and so the dirty pages must be saved to disk, even if there are only a single "dirty" array element in that page.
In the 1970's people believed in virtual memory and some system were originally delivered with less than 1 MB of physical memory :-)
The working set size limits how big arrays can be readily transposed, that is how many "dirty" pages can be in physical memory at one time. If the output is suboptimal the same page may have to be written out multiple times. For this reason it makes more sense to store the output optimally, since a completely dirty page needs to be written out only once.
You can write" virtual memory friendly" cods in C if you start from the beginning. Using some existing Fortran library routines and just change the syntax to C will be a disaster if you do not alter the innermost/outermost loop order.
PDP-8, 4K 12-bit words. I simulated a steamship propulsion system, graphed step response on a teletype, showed it to some owners and a shipyard, and sold stuff. Bunch of LASH ships.
An other example of virtual memory misuse.
In most MS Windows file programming examples the file is opened, the size is determined, a virtual memory table as big as the file is created and then the file is read into the table in one operation, before any processing is done to the file contents.
This works well as long as the file is much smaller than the working set (and ultimately the physical memory size).
Things get ugly when the fie is multiple times the working set size.Determining the size of the file and allocating in virtual memory works OK regardless of file size. However start reading to the table will cause those pages to become "dirty". When the working set becomes full with dirty pages, those dirty pages must be written to the page file.
Only after this, more pages can be loaded from the input file. If the input file is on the same disk as the page file, the disk head constantly needs to jump between these two files (seek time).This is done multiple times with a few pages at a time.
Ultimately the whole file has been copied into page file and is read from the page file when actual file processing starts.
Decades ago I observed a simple video display program that took half an hour to just to load a huge file into page file :-).
A better way of handling big files is memory mapped files. Open the memory mapped file and you get a virtual address if the table. Referencing a byte in a table will load that page into physical memory from the input file and the contents can be used. For input files, such pages are clean, thus no need to write the page into page file. If the working set becomes full, simply discard such pages and load new pages into physical memory. If the original page is kneaded again, it is reloaded from the input file.
If the application only needs parts of the data in the file, it can load only those pages, reducing disk I/O. Compare this to the MS method, in which the file is fully loaded from input file (and written back to page file :-).
Have something to add? Share your thoughts — no account required.
Ask the community — no account required