What kind of programming can one do without even that level of mental model of what a computer does?
What kind of programming can one do without even that level of mental model of what a computer does?
Believe or not, pointers can be difficult to grasp as a concept for people who aren't used to this type of mental model.
If you didn't struggle with it, good for you. But there's no need to look down on others who are trying to learn. I should also add that Software Engineering and Programming aren't necessarly synonyms. Some programmers aren't SWE and that's OK.
If you're a "fake programmer" like the parent is trying to imply, don't lose hope. Continue to learn at your own pace and you'll eventually catch up.
You probably shouldn't put words in other people's mouth.
I don't think he was calling the people fake, but merely asking how effective they could be at programming without an understanding of memory.
It's a good thing. Most of the time for most of the people, it's better to work closer to your problem domain than to the CPU.
Having a rough understanding of what memory is at a very rough high-level grasp ("numbered byte-size cells" isn't very in-depth after all) doesn't preclude one from working "closer to one's problem domain", likewise lacking such grasp doesn't bring one any closer to one's problem domain.. what am I missing?
If you need to understand memory to use a language, then it's not abstracting well enough.
In the book, "Mythical Man Month", Fred Brooks talks about the two kinds of complexity in solving problems with computers. There's the "essential complexity" that's there because the problem you are solving is actually complex, and then there's the "accidental complexity" that's not actually required to solve the problem, but to make the computer happy.
Let's compare C arrays and Python/C# Lists. For my pretend problem, I need an ordered, index-able set of things.
With the C array, I need to know how big to make it before I create it. I need to allocate the memory that is used before I use it, and I must deallocate that memory when I'm done with it. I might underflow or overflow the array and allow Eastern European hackers control over my server and data. Even if I checking for overflows and underflows in all the proper places, I also have to add code to every one of those places handle each possible error.
Whereas in C# and Python, I just make a new list and stick things into it. When it goes out of scope, it disappears automatically.
Python and C# move me closer to the actual problem being solved by removing this "Accidental Complexity". When complexity removing is done well, it also removes the requirement for the programmer to know about numbered cells of memory, because numbered cells of memory is "Accidental Complexity" for the problem domain.
Now when I know how the computer is actually working, it does bring benefits. Today, in fact, I'm writing C code for an embedded ARM chip. Knowledge of memory numbers is a little required here. But for most software developers, knowing how memory works is not a requirement for working software. Even memory-as-a-numbered-set-of-cells is still just a huge abstraction from how the memory is actually being handled by the hardware.
But that is essential complexity when you need to reason carefully about memory use.
JavaScript? Python?
var a = 1
var b = 2
You have to know that these values are stored in working memory, not on hard drive or Google's servers or Martian stone tablets.Understanding the implementation details is valuable, but I'm not sure why you think it's necessary to program?
If "a = b + c" takes a second to execute, you have to take that into account. The programs that people wrote for 1950s computers were very different from today, even though the language semantics might be essentially the same.
On the other hand, this discussion is helping me understand why the web development world is full of weird database-backed Rube Goldberg machines that can spend milliseconds to access a few bytes of data that were already in RAM.
But it doesn't, so you don't.
Sure understanding performance is necessary to build more complex or higher usage systems, but not understanding it does not preclude "useful programming".
But it doesn't, so you don't.
How do you know it doesn't? What if assigning to 'a' writes to a remote database and waits for the write to be confirmed?
More to the point, how does a new programmer know that is not the case? The average person's expectation of computation speed is shaped by the experience of using server-side web apps: you click on a button, a new page is loaded from the server taking multiple seconds to finish.
To understand that an assignment doesn't run that slow, you need to be told that. Surely explaining local memory would be part of that.
Not really. You just try it, and notice it ran instantly. You don't really have to care how it happens to run behind the scenes, as long as you have a working model of the semantics. That's the entire point of most abstractions, to make it so that you don't have to think about all the details when you don't want/need to.
Understanding this fact does not strictly imply having a basic understanding of memory, but it gets pretty close to it. I would personally be weary of some who calls itself a programmer or software engineer and couldn't write this article themselves.
The only relevant parts is that (1) they are immutable and (2) they are compared by value.
That being said nowadays I'm sure many more coders start with something like Javascript instead of 8bit controllers, so I'm sure these types of articles are very valuable to many.
Maybe the first couple of hours when I still hadn't read the DIM, DATA, READ, POKE and PEEK manual pages.
Just like on Dave Cheney's post, seeing a few box examples was enough to get it.
It just felt natural on how a computer was working, typing example after example, to a 10 year old version of myself.
I'm just surprised that an explanation geared for programmers would need to also explain that variables are stored in local memory, or what RAM is. (Again, there is nothing wrong with explaining that.)
Sadly, yes. Universities have moved away from teaching C. In ancient times, when I went to school, you'd start with an intro class in Pascal, then you'd take a data structures class in Pascal, and then you'd take some harder class in C.
About half of the people in the C class would drop out of Computer Science when they hit pointers. As someone who gets pointers pretty much instinctively, I didn't get it, the concept seemed really intuitive to me. But apparently that's not true for everyone, some people really struggle with it.
I think it really doesn't help that CS has moved away from C as a teaching language. C can be viewed as a pleasant, portable, assembly language. As such, it lets you "feel" the bare metal, much more so than a scripting language like Python or Javascript.
Do I have to buy what you're on from some guy on the street or is it available as a prescription?
> As such, it lets you "feel" the bare metal, much more so than a scripting language like Python or Javascript.
C hasn't been bare metal since the PDP-11. There are like eight layers of abstraction between
char *foo = "bar";
and the "bare metal"; I don't know why people are desperately clinging to this "C is basically portable assembly nonsense".I'm not sure what you mean by layers of abstraction (type checking? optimization?) but C code often does have a pretty straightforward translation to assembly.
Perhaps you had a bad experience and can clarify what you mean?
So the compiler is obviously one layer. Then there's the assembler and the linker. Does the C runtime count too?
You think you have a "string", but it's actually just an address to a (hopefully) nul-terminated chunk of "contiguous" virtual memory.
If you wanted to read the first byte of that array, it would first go through the OS's virtual memory system, so that's one rather large abstraction. (I'm lumping in the hardware's virtual memory support here, too)
Then when you actually access a piece of "real" memory, there are a number of caches between your data and the request to fetch it. And what about the DRAM itself? Can it access only a single byte of memory at a time, or is that too an abstraction?
Instruction decoding is one or two layers at least, since chances are the processor doesn't actually execute x86 opcodes directly.
And when you run out of software abstractions, how many levels of abstraction is there in the actual hardware?
I only have vague ideas of what actually happens at this level, and whenever I stop to think about it, it's pretty amazing our software stacks work at all...
Other than for teaching "an industry language" I don't immediately see much reason to teach C and Pascal - but I suppose the "modern" equivalent would be Python, Cython, C and assembler, followed by haskell/(oca)ml, Prolog and/or a lisp/scheme - with the benefit of showing C interop along the way.
Sure, sixy seven lines of assembly handily beats arcane crap like:
obj->ops.tbl[BLAH]->func(obj, &obj->x, arg);
Want to take an integer in a register, then add another register's integer multiplied by 8 or 4, and then a fixed offset?Just use LEA (load effective address) and don't comment anything.
Let the reader figure out that no pointers are involved.
[edit: 99% sure is sarcastic]
On the constrained part of things, there's no pointer arithmetic, and in Standard Pascal, there's no "address of" operator at all - a pointer can only point at dynamically allocated memory block, not at global or local variable, or some memory location inside another block. Consequently, there's also no pointer arithmetic. This is sufficient to make linked lists and other similar data structures, but also makes the concept much more opaque compared to C (i.e. it's less obvious that it's really a numeric address).
On the syntax part, I think the big problem with C is that the moment you start dealing with pointers, the arcane rules for declarator precedence are in play. Pascal, OTOH, has a very regular type syntax, which in case of pointers is also easier to read - you just read ^ as "pointer to", and so ^integer is "pointer to integer". Same thing for dereferencing - again it's ^, but there you read ^ as "points to", and so a dereference like x^ becomes "what x points to". And there's also no confusion with any other operator, since ^ is reserved for pointers alone, and it has a fairly obvious mnemonic to it.
If your language treats things in terms of numbered cells and nicknames, then you need a mental model of that.
If your language treats things in terms of reverentially transparent values, then you need a mental model of that.
For non-early-apprentice-level programming, one could also use the mental model of what's below the language runtime.