What is "the stack"? - jor-el http://jvns.ca/blog/2016/03/01/a-few-notes-on-the-stack/ <comment><AUTHOR> It started with the x86 and PDP-11 thing. Some CPU architectures have a specific stack pointer register, and some don't. IBM mainframes don't have a dedicated stack pointer; the stack is a software construct. Neither do SPARC machines.

There are also real stack machines, where instructions take operands from the stack and push results on the stack. The Burroughs 5000 and the English Electric LEO-Marconi KDF9 introduced that architecture around 1958. It lives on in the x86 FPU register stack.

FORTRAN and COBOL originally forbade recursion. Compilers could allocate all temporary memory at compile time. Stack overflow is impossible. Some real-time systems still work that way.

<comment><USER2> Some microcontrollers (e.g. some PICs) even have a hardware stack for storing return addresses. This stack is on the processor die like the registers and not in the RAM which makes it even more _fundamental_.

<comment><AUTHOR> Yes, and the PIC's return point stack is tiny. 2 (!) on the smallest machines, 8 on most, 31 on the "high end" PICs.[1]

[1] [http://embeddedgurus.com/stack-overflow/2009/04/pic-stack- ov...](http://embeddedgurus.com/stack-overflow/2009/04/pic-stack-overflow/)

</comment></comment></comment><comment><USER3> This only scratches the surface of the topic. Here's a fine article that talks about implementing a crash handler for JNI that goes into some of the more complex issues of multiple stacks, signal handling, stack unwinding, and calling across languages:

[http://blog.httrack.com/blog/2013/08/23/catching-posix- signa...](http://blog.httrack.com/blog/2013/08/23/catching-posix-signals-on- android/)

Aside: it's interesting how complex things which I learned in my younger years have become. From understanding how a car operates and being able to perform maintenance on it (compare rebuilding a carburetor or adjusting the timing to fuel injection and computer controlled distributorless electronic ignition, etc), to this topic, computer architecture. I'm glad I first learned these things when they were simpler. I think they might seem daunting to start learning about today. Though I guess like anything else, you start at the surface and keep digging till you're satisfied you understand the topic well enough. It's just that if you like to get to the bottom of those rabbit holes, they're all so much deeper now. Shrug.

p.s. I really enjoy reading the author's posts. They are often about something I'm familiar with, but it's neat to read someone writing about learning these things through fresh eyes. I also sometimes realize I don't know something as well as I thought. So thank you for sharing.

<comment><USER4> Conversely, I often think how lucky I am to have entered the industry at this point.

I learnt HTML by initially downloading websites using ctrl-s, and then editing them in notepad. I learnt HTML/CSS, and then JavaScript, and then other languages.

I had the advantage that I had a GUI text editor. While I'm now quite comfortable using VIM and command-line editors, I sometimes think if I had tried to become a developer before the advent of GUI editors the learning curve would have been too steep.

Perhaps under the hood things are more complex, but the interfaces have improved.

<comment><USER5> Interfaces have improved because the scope of the thing has grown.

I learnt HTML in 1995, I think shortly before HTML 2 was released. It was tiny back then. Using anything other than a text editor was inconceivable (I doubt there was any tooling back then). CSS and JavaScript didn't even exist. We had CGI for emailing form content, but most of the web was static.

By 1998 I was convinced that every app ever would be online. Today I've come full circle, avoiding web dev like the plague (too _many_ tools) and stick with desktop and phone apps.

</comment></comment></comment><comment><USER6> "This isn't a theoretical question at all -- Rust actually has a different calling convention from C"

Technically correct, but not at the register/stack management level: LLVM still controls all of that, Rust only chooses the order of the arguments and whether they are passed "directly" (in registers or on the stack, when registers are exhausted) or "indirectly" (pointer to the value, whether it's on the stack or somewhere else).

So the following statement, "which means it sets up its stack differently" is incorrect: even if Rust wanted to, it couldn't do so with the LLVM backend.

<comment><USER7> In turn, isn't LLVM's stack management and argument passing dictated by the hardware's ABI? ARM, for one, publishes its calling convention in AAPCS (ARM Architecture Procedure Call Standard) which establishes the calling convention on the C stack.

<comment><USER8> ARM and modern x64 have pretty rigorously-defined calling conventions, yeah. x86, on the other hand, has six or seven different ones, and it was up to you as a C programmer to choose which one to use for each given function, by sticking e.g. a __stdcall or a __fastcall in your typespec.

<comment><USER9> x64 on Linux has a different calling convention than x64 on Windows.

</comment></comment></comment></comment><comment><USER10> `push` _decrements_ the stack pointer on x86 architecture, unlike on ARM. The stack is strange in that it grows downwards. That is also why in the disassembly of the `blah` function the argument is temporarily stored in `ebp - 4` as ebp points to the top of the stack (which is at the lowest address).

I also wouldn't really say assembly follows the C stack pointer. The C language makes no assumptions about stacks, stack pointer or return addresses. It just describes "functions" to which the execution can be transferred and from which can be returned. How this is implemented, is up to the compiler designer and is platform dependent. I wouldn't be surprised to find out there were platforms without a stack/stack pointer but with a C compiler

<comment><USER11> > `push` decrements the stack pointer on x86 architecture, unlike on ARM.

Why do you say "unlike on ARM"? In 25 years I've never seen anything but a full, descending stack used as the program stack. You _can_ have ascending stacks, but that's more an artifact of the fact that `pop` and `push` (which didn't exist in the assembly language until Thumb) are just specific uses of the general multiple load/store instructions `LDM` and `STM`, which can "write back" an incremented or decremented base register.

</comment></comment><comment><USER12> And just wait until you find out about Harvard architecture[1] CPUs that don't have a stack in the same sense that C has a stack—they generally have a call stack that is only manipulated implicitly by JSR and RET style instructions. It doesn't co-mingle return addresses with stack variables, like x86 (and von Neumann architecture[2] CPUs).

[1] [https://en.wikipedia.org/wiki/Harvard_architecture](https://en.wikipedia.org/wiki/Harvard_architecture)

[2] [https://en.wikipedia.org/wiki/Von_Neumann_architecture](https://en.wikipedia.org/wiki/Von_Neumann_architecture)

<comment><USER13> At some point I was messing around with writing a toy VM and the choice of co- mingling return addresses and what where the functions arguments felt weird to me so I split them into two different stacks. It actually worked out. I mean it meant I diverged from the book I was using to do this but that was part of the fun to see which parts were simpler and which parts were more complicated in my design.

This was the book I used in case folks are curious [http://www.springer.com/us/book/9783642149085](http://www.springer.com/us/book/9783642149085).

<comment><USER14> See Forth, Factor a.o. which are "harvard" languages.

</comment></comment></comment><comment><USER15> This is great - I'm self taught and have been working for years with no idea what the stack is - I'd love one for this "heap" thing I keep hearing about, as well.

<comment><USER16> Things like the stack and heap and many other things (like memory mapped I/O, interrupts, etc) are often taught in first year university courses under a name like "introduction to computer organization". There are many online courses you can do for free, or you can simply go to a book store and pick up a text book. Although none of it is something that you desperately need in order to work as a programmer these days, it's one of those things that will undoubtedly be useful almost every day, so I highly recommend it.

As for the heap, I noticed another description, but I'll have a go at describing it in a slightly different way. Back in the old days you had a big chunk of contiguous memory. It started at address 0 and ended at address 65535 (if you were lucky enough to have 64K of RAM!).

As you saw in the article, you need to set aside some of that memory for the stack. In most languages that are compiled to machine language, the stack holds storage for variables local to a function as well as the function return address (the object that holds all the information for one function is called a "stack frame"). As others have said, other organizations are possible, but this is the most common.

Allocating memory on the stack is ideal because it is really easy to allocate and deallocate. When you enter a new function, you look at how big each of the local variables are and you simply move the "stack pointer" that many bytes (either up or down, depending on the architecture of the machine). When the function is finished, you simply move the stack pointer back to the start of that stack frame. Super easy and super fast.

The problem is that as soon as your function finishes, the variable is deallocated. So let's say you have a function that loads a picture from disk. You make a big array in your picture loading function, put the picture data in it and return it from the function... uh oh... As soon as the function ends, the memory is deallocated :-(. That data is "gone" (what's worse is that the data is still there, so it will appear to work until the stack grows big enough to overwrite that data -- at which point your picture will be corrupted). So we need a way to allocate memory that will stick around until we tell the system that it is not needed any more.

That's what the heap is. I can call a system function (usually called "malloc", which stands for "memory allocate") and say "I want 4K of memory". It finds a contiguous chunk of 4K of memory, makes a note that the memory is in use and then gives me a pointer to it. I can then use that pointer to write into the memory. The system will not allocate any memory in that area unless I tell it to "free" the memory (usually with a call to something called "free"). After that it can be used again.

The place the system looks for in the memory for this kind of allocation is called the heap. So you can imagine the big block of memory in a computer is divided up into at least 2 sections: the stack and the heap. Often a computer system will put them at the opposite sides of the memory so that you can grow the stack as much as possible. So I might start the stack at 65535 and grow downward. And I might start allocating the heap from 0 upwards. In practice there are other things you need to reserve memory/addresses for, so this is not how it really works, but you get the idea.

Many programmers like allocating from the heap because it is easy. You don't have to worry about the scope of your program. You allocate a variable and it is there until you tell it to go away. But there are a couple of problems. First, if you forget to free the memory, it _never_ goes away. This is called a "memory leak". Also, you might accidentally try to use the memory after you freed it, resulting in the same corruption noted earlier. But there is yet another problem.

Let's imagine that I allocated 1024 40 byte strings. That will take up 40K (almost all of my memory on this hypothetical old machine). Let's say that every second string is only needed at the beginning of the program, so let's free them all. That frees up 20K. However, the heap is now "fragmented". It has 40 bytes allocated, 40 bytes unallocated, 40 bytes allocated, 40 bytes unallocated... If I want to allocate 45 bytes, I will have to walk through 512 unallocated blocks, noting that each is too small, before I decide to allocate at the end. This is very slow. If there isn't a 45 byte chunk available, then my memory allocation will fail, even though I have 20K of free memory.

So, for many old timers like me, we favoured allocating on the stack. This leads to fast, efficient, safe code that is also surprisingly elegant. Unfortunately, it is also hard to design ;-)

These days, operating systems do a lot behind the scenes to make sure that you don't fragment your heap too much, etc, etc. Modern interpreted languages use garbage collection and allocate on the heap incrementally -- as if it were stack allocation. Occasionally they wander through and deallocate unused variables and compact the heap. Some of the algorithms used are very sophisticated and quick.

I keep thinking about designing a functional language with stack allocation, though... It appeals to my roots ;-).

Hope that description helps. Keep in mind that many details will be incorrect for any specific system. I mostly just tried to make the description simple, not accurate.

<comment><USER17> I don't know if it's still the case, but past versions of the Chicken Scheme system [1] implemented a remarkable stack-based allocation method from Henry Baker, fondly called "Cheney on the MTA" [2]. If you like thinking about how functional languages interplay with stack allocation, you would probably enjoy bending your head around this. :)

[1] [http://www.call-cc.org/](http://www.call-cc.org/)

[2] [http://home.pipeline.com/~hbaker1/CheneyMTA.html](http://home.pipeline.com/~hbaker1/CheneyMTA.html)

<comment><USER16> Sorry for the slow response. I'm reading this now and enjoying it very much. Thank you!

</comment></comment></comment></comment><comment><USER18> What came first in modern systems was the ABI standards documentation, which for Linux is the System V ABI, which is apparently followed even on BSD.

[http://wiki.osdev.org/System_V_ABI](http://wiki.osdev.org/System_V_ABI)

So System V came out in 1983, which postdates the introduction of the x86 architecture because the IBM PC was x86 from day one and it first came out in 1981. (I'm sure the 8086 is older, but it doesn't really matter here.)

Of course, it isn't the only standard out there for x86. Microsoft exists, after all.

[https://en.wikipedia.org/wiki/X86_calling_conventions](https://en.wikipedia.org/wiki/X86_calling_conventions)

Anyway, all of these standards have to specify which registers get saved by the called function and which get clobbered (and, therefore, must be saved by the calling function if their values are important) and you can't know which registers will exist on a given ISA until it exists, so the specific System V ABI for the x86 couldn't possibly have existed until the chips did. Ditto the System V ABI for the x86-64, the MIPS, and all of the other ISAs for which there is such a document.

However, chip designers aren't stupid. They know that their chips will be used to run binaries generated by C compilers, and that C compilers like stack frames and registers. Therefore, modern ISAs are designed with those things in mind, and I wouldn't be surprised if at least a few chip designers worked with one eye on some ABI documentation.

(Compare modern chips with older minicomputer and mainframe ISAs, where call stacks weren't always available and where subroutine calls sometimes involved self-modifying code. The PDP-8, for example, did subroutine calls by writing the the return address to the first (12-bit) word of memory in the subroutine, and then jumping to the address just past it; returning was a simple matter of jumping to a memory location loaded from a known address, but recursion was effectively impossible. The PDP-8 was a fine machine for assembly language programmers, but almost perversely unfriendly to modern mid-level languages, such as C and Pascal.)

<comment><USER19> Burroughs, IBM mainframes, Ada Machines (by Rational), Xerox Parc and ETHZ workstations are probably the best examples of more higher level friendly architectures.

Or at least the better documented ones.

</comment></comment><comment><USER20> Bit of a nitpick, but ELF binaries are not used "only in Linux". OS X (Mach) and Windows (PE) are really quite exceptional here.

System V R4, HP-UX, NetBSD, Linux, Solaris, AIX, IRIX, FreeBSD, OpenBSD, DragonFly BSD, OpenVMS, QNX, Syllable, MINIX, BeOS/Haiku, RISC OS, GP2X, Dreamcast, Gamecube, PSX, PS2, PS3 (maybe NetBSD or FreeBSD ish), PS4(based on FreeBSD), AmigaOS 4, Morph OS, AROS, Open Firmware, and probably a whole bunch of other systems use ELF binaries.

<comment><USER19> I think you can had existing mainframe OSes to the exceptions list.

<comment><USER21> I would have thought so, but this [https://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/...](https://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.cbcdu01/cons_sf_1.htm) suggest maybe otherwise.

<comment><USER19> So it seems, thanks for the hint.

</comment></comment></comment></comment><comment><USER22> This question reminds me of this Twitter thread, started by @raymondh:

Programmer survey: Do visualize consecutive memory locations as running left- to-right, right-to-left, top-to-bottom, or bottom-to-top?

[https://mobile.twitter.com/raymondh/status/69510373753937510...](https://mobile.twitter.com/raymondh/status/695103737539375104)

<comment><USER23> Left-to-right for me; vertical is confusing because I like to put address 0 at the top and address MAX at the bottom, but then the stack "grows down" and I get confused.

<comment><USER24> Strangely, on the processors I'm familiar with, the stack would grow up in that orientation.

</comment></comment></comment><comment><USER25> > I found it pretty surprising that the x86 assembly instruction set knows > about the C stack pointer and how the stack in C is laid out. Of course, you > could invent your own new smart stack format, but you wouldn't be able to > use the callq and retq instructions to call functions.

I find it pretty amazing how modern "programmers" are lacking in knowledge of basic computer science concepts. Let me nit-pick this statement as it is obviously wrong.

The x86 assembly language knows _ABSOLUTELY_ nothing about the "C stack pointer and how the stack in C is laid out". I will now illustrate why the first part of this statement is wrong.

You can have a bare-metal x86 device that is only programmed though assembly and push/pop would still be available. You are clearly confusing the roles of the compiler, operating system, and the language your program is written in. On a modern operating system like Linux, each program, when started, runs in a new process, which has its own view of memory due to the virtual memory system. Each program has its view of memory split into several sections, and one of them is allocated as "stack space" (it's usually the high memory addresses but this is architecture and/or OS dependent). When the program is executed, %rsp would be set-up appropriately by the OS, and on context switches it would save/restore it. Moreover, the actual address of your stack in real memory is different for every program since each process/program has its own mapping of virtual to physical memory, again provided by the OS.

Now, the second part about the "layout of the stack". The language you write your program in (in this case C) knows _ABSOLUTELY_ nothing about the layout of "the stack". However, when you give your source code to the compiler, it will analyse it and, because C is low-level and staticly typed, will infer _HOW_ it actually needs to lay out the stack _FOR you_. The output of the compiler is assembly code, and the assembly code produced "knows" about the layout of the stack because it has been written that way, generated by the compiler. It is, actually, the compiler that knows about all of this, not the source or assembly language.

Also, the example with python was a bad one - python is an interpreted language, and AFAIK it has no concept of a stack, and even if it does, it is the interpreter that allocates frames for it's own computations, not the program that you are running. And, moreover, even if python does allocate stack frames, they are most probably on the heap since it needs to do so dynamically (again, since it's not compiled but interpreted).

<comment><USER26> > python is an interpreted language, and AFAIK it has no concept of a stack,

Here, I could say, "I find it pretty amazing that old-timey[1] 'programmers' fail to understand modern VM architecture". In fact, Python's interpreter (cpython) is partly based on the concept of a stack.

But instead, I'll just explain that most modern VM's are either stack-based or register-based. Stack-based VM's, like Python's, are (not surprisingly) based on a virtual machine that uses a stack as it interprets Python's bytecode. Yes, not the same level of abstraction as the call stack, but it's still a stack.

So instead of expressing dismay at how little modern programmers know about your little corner of the programming world (low-level systems programming), why not spend some time pondering about how so much programming has moved up the stack, and how abstractions have grown multifold.

In the 1970s and 1980s, it used to be that the typical self-taught programmer had to know all the details low-level C and assembly, because that was almost all there was _to_ know, unless you were a high-level Lisp hacker.

I mean, I'm a little surprised at how little some C kernel hackers know about how the modern Web works (particularly regarding async programming patterns; eg, been asked by one why I didn't just use a mutex somewhere in JS program, wasn't trolling.). But then I realize that there's just too much for any but the _most_ exceptional programmers to truly understand the full modern stack, from system architecture, to GPU, to networking, to Web, on so on.

Why not instead welcome how this particular web-focused programmer is interested in these low-level concepts? Is it that it wouldn't give you as much of a chance to show off your knowledge?

1\. Said by another old-timey programmer.

<comment><USER27> VMs, and VM-based languages, are applications that run on top of all that kernel programming.

Applications come and go so there's no reason to feel amazed that not everyone know how the Python VM works - especially considering the details aren't considered a core part of the Python curriculum, and they're almost completely inaccessible to a typical Python user.

But not understanding the heap or the stack has real implications for application performance and stability in whatever language or VM you're working in. The abstractions have gotten more abstract, but developers who no longer understand what happens when you run out of memory, or have a buffer under/overflow, or your stack explodes because you're using recursion without tail calls, are definitely a _bad thing._

You seem to be arguing that anyone who does web or VM dev doesn't really need to know what happens inside a computer. I think that's an unhelpful view, because it implies that all those abstractions "just work" and no one who uses them needs to care how.

Do they really "just work"? I think the evidence suggests they don't. Perhaps if developers understood hardware better that could be improved.

<comment><USER26> > VMs, and VM-based languages, are applications that run on top of all that > kernel programming.

I'm guessing the vast majority of all modern programming is done using VMs: Python, Java, C#, Lua^, JavaScript^, etc. Basically, if your language uses a runtime, it's likely using a documented or undocumented bytecode and VM. They're pretty important to understand.

> You seem to be arguing that anyone who does web or VM dev doesn't really > need to know what happens inside a computer.

That's not my argument. I highly recommend new programmers to understand as much of machine architecture as reasonable. I'm just arguing that there's no place for a systems programmer to be so dismissive toward a web programmer because he/she doesn't know his part of the stack as well as he does. There is always going to be a gap in knowledge about low-level programming between these two specializations. That gap is no reflection on the intelligence or competence of the higher-level programmer.

In this particular case, I believe that Julie has only been programming for a few years. If that's the case, and assuming she only retains a fraction of what she writes about, she's further along than most of us were at that point (me included). Just because many of us bluff and bluster our way through interactions with our peers, and Julie is up-front about her state of knowledge, doesn't mean that she's an inferior programmer (at all). I suspect her honest curiosity will carry her along to the top of our profession in due time.

So if the parent had written something like, "it's _so_ important for new programmers to work on this type of material, and it's heartening to see these kinds of blog posts from younger programmers", then I would have applauded.

That also would have been more in line with the HN guidelines ("avoid gratuitous negativity"), rather than the approach that was actually taken.

^ If you want to advance the "Lua, Python, and JS" aren't VMs, but rather interpreters, you'll need to convince the likes of Mike Pall and Lars Bak that they're not working on a VM (both have explicitly referred to their creations as "VMs").

</comment></comment></comment></comment><comment><USER28> I have a lot of fun explaining to people that the architecture I work on (IBM Power aka PowerPC) uses calling conventions that for many function calls doesn't touch the stack whatsoever. :)

<comment><USER29> How does it work? Pass the return address in a register and have enough caller-saved registers that leaf functions can often do without spilling? Or is there a more sophisticated mechanism?

<comment><USER28> a) Return address is passed in the "link register" \- our call instruction is "bl" (branch and link) and return is "blr" (branch link register)

b) We have 32 general purpose registers - the ABI defines a certain range of registers (8 general purpose registers + a bunch of floating point and vector registers) for passing parameters

c) The register range allocated for passing parameters is designated as "volatile", so the caller can't rely on them coming back unmodified. This gives you a few registers to play with.

(NB: I'm not hugely experienced in PPC assembly programming, I've just had to touch it a couple of times and so I've read bits and pieces of the ABI, don't trust what I say here...)

<comment><USER30> Aha, but if you have at least function 2 calls, assuming none is inlined, you HAVE to use the stack to save the prev LR. I actually think it's one of the default processes at the beginning of a function, but maybe the compiler optimizes in many cases.. I'm really curious if you can find some assembly examples of functions where you don't use the stack. I've seen it on Renesas MCU's and on PPC but only for veery simple functions.

Also, the architecture isn't exactly the one to blame for this, it's more dependant on compiler calling conventions. I see things in the arch that facillitate this, but I see it possible to implement this mechanism with or without this arch support. I've only seen certain registers being reserved for something in the compiler docs not the MCU docs.

Eh, maybe I'm rambling.

<comment><USER28> Oh, yeah, only for leaf functions. Obviously not for multiple levels of calls.

My understanding is that PPC encourages register based parameter passing just by virtue of having a tonne of registers.

</comment></comment></comment></comment></comment><comment><USER31> "I found it pretty surprising that the x86 assembly instruction set knows about the C stack pointer and how the stack in C is laid out. Of course, you could invent your own new smart stack format, but you wouldn't be able to use the callq and retq instructions to call functions."

Exactly the problem that everyone runs into coming up with more secure alternatives to C or existing stack. One example was a 10+% penalty for MULTICS-style, reverse stack due to indirection necessary. It's why I tell people to use a RISC system if they want to build security on. Ideally, microcode will come back with another HLL-to-microcode compiler so we can implement secure alternatives directly as instructions. One could also implement abstract machines like JVM's that way with no attacks through abstraction gaps. Not to mention efficiency and arbitrary atomic actions.

</comment><comment><USER32> This sort of reminds me of stack virtual machines vs register based virtual machines.

That is the low level code (assembly/bytecode) of function calls in a programming language is very different depending on whether its stack or register based.

</comment><comment><USER33> Usually I browse quickly the HN comments before reading (or skipping) an article, in this case I browse through the blog post first and then I thouhgt, "now the HN comments are going to teach me a lot, pointing out all the errors in this post", wasn't dissapointed.

</comment><comment><USER34> "I was really surprised that assembly instructions make assumptions about how memory is organized and what information is in which registers."

This layout is a part of the specific architecture the compiler is generating the assembly code for so it better know where the stack pointer is stored on your platform :)

It's basically the same way as if you were manually writing Assembly code yourself - you would need to know what registers are used for what purpose on your platform.

</comment><comment><USER22> Partly off-topic, but interesting, IMO:

This thread (the word "stack") triggered a memory of stack machines, which I had read about much earlier, in computer mags such as BYTE. Looked it up just now, and saw:

[https://en.wikipedia.org/wiki/Stack_machine#Virtual_stack_ma...](https://en.wikipedia.org/wiki/Stack_machine#Virtual_stack_machines)

which says that the JVM, CPython and a couple of Ruby VMs are virtual stack machines.

</comment><comment><USER22> Yet another wrinkle or dimension to this is the C vs Pascal calling conventions [1]. I remember from Win 32 SDK days (MS VC, Borland C, etc.), e.g.:

"long far pascal" as part of the type decl of functions.

[1] which was about the order in which function args get pushed onto the stack before the jump to the function is taken - L to R or R to L.

Used to wonder what non-tech people would think if they heard a programmer saying such stuff out aloud :)

</comment><comment><USER35> Great post!

If you liked this kind of descent to the low-level realm, the post author (Julia Evans) did a great presentation on Pycon 2015:

[https://www.youtube.com/watch?v=5v6o-VsLAew](https://www.youtube.com/watch?v=5v6o-VsLAew)

Sometimes when shit hits the fan it's nice to know what is going on behind all those layers of abstraction.

</comment><comment><USER36> Many ISAs do not provide any specific stack handling instructions, and yet a C ABI is based on a stack model very similar to x86 one. Instructions are irrelevant, ABI is only a convention.

<comment><USER37> Sure. But I think it's fair to say that a structure that's part of the ABI is more distinguished/fundamental than an ordinary datastructure defined in the language.

</comment></comment><comment><USER38> If a stack grows down how do you generally draw it on paper? Do you start with some arbitrarily high address like 8000000 and just subtract from it? What happens when you get to 0?

</comment><comment><USER39> FPGAs are a way to avoid stacks too. E.g use c\ash to convert Haskell to a circuit.

<comment><USER36> Most modern FPGAs got two-port block rams. Ideal for stacks and FIFOs. Many non-trivial designs are using stacks one way or another.

</comment></comment><comment><USER40> After reading about FP, TCO, the question shifted from `what` to `why`.

<comment><USER41> In case anyone is as confused as I was at first, agumonkey is referring to the fact that Functional Programming languages are capable of Tail Call Optimization, which allows functions to be composed without adding a new frame to the stack.

<comment><USER42> It's kind of interesting that TCO goes together with FP, because logically it makes at least as much sense for OOP, as Guy Steele pointed out at [http://www.eighty-twenty.org/2011/10/01/oo-tail- calls.html](http://www.eighty-twenty.org/2011/10/01/oo-tail-calls.html)

<comment><USER37> The concept of combining many values to get another value _of the same type_ is the heart of FP - function composition is just the most prominent example of it. That definition of IntSet is effectively a cons list, a very FP- oriented data structure. It's not an example of OOP needing tail calls because it's not an example of OOP style (at least, if we believe that's something disjoint from functional style) at all.

<comment><USER42> I don't consider OO to be disjoint from functional; the first OO language was the untyped lambda calculus (as William Cook's said). In the taxonomy at [http://www.paulgraham.com/reesoo.html](http://www.paulgraham.com/reesoo.html) we're looking at 2. protection and 6. "all you can do (with an object) is send a message", like how all you can do with a function is call it.

I don't agree that FP owns compositionality. In the 80s and 90s I used to have to argue for the value of functional programming; nowadays the closeminded attitudes come more from the "other side", and from one POV that's heartening progress, but from another it's silly to be running culture wars around technical ideas.

<comment><USER40> I've never seen an OO article / book that managed to demonstrate composition even at 1% that the average Haskell book does. I'm trying not to take sides too much, but I grew up in OO-land, left and keep getting mesmerized by what the FP guys have been doing. Most recently monadic thinking (I know, monads) but bind as an abstract composition operator is maddeningly beautiful. Although I've heard that Monads themselve don't compose ~_~;

<comment><USER42> It's great how Haskell and friends keep spreading, isn't it? Here is an OO book I like: [http://www.erights.org/talks/thesis/](http://www.erights.org/talks/thesis/)

</comment></comment></comment></comment></comment></comment></comment><comment><USER43> Well done.

I feel old, though.

</comment><comment><USER44> Very informative, thanks for the summary!

</comment><comment><USER45> I hoped to find something about "the stack" as in "full stack development" (DB, middleware, frontend etc) because _that_ stack also needs some sorting out.

<comment><USER36> That hipstor buzzword hardly deserves "THE" in front of it.</comment></comment>


Open Source Alternatives to Google Docs - <AUTHOR> https://cloudron.io/blog/2020-01-07-opensource-alternatives-to-google-docs.html <comment><USER2> If you're using a service hosted by someone else, then it doesn't matter if it's open source; you're using someone else's closed environment. In that case you're just as well off using Google or Microsoft. Probably better off, since they aren't aren't hosting on a shoestring budget.

The point to having it open is so that you can host it yourself and modify it yourself.

</comment><comment><USER3> I wish OnlyOffice would remove the 20 max connection limit on the community edition.

<comment><USER4> If it is opensource then you can remove the user limit I would think?

</comment></comment><comment><USER5> Not mentioned in this list — it's unfortunate that Framasoft is shutting down many of its online and free (based on open source, of course) services in this space. It was good enough for simple needs.

<comment><AUTHOR> That is indeed a shame and I was also not aware of them shutting down some of their services. But as far as I know their text document editing tool is a slightly improved etherpad, which is mentioned in the article.

</comment></comment><comment><USER6> iCloud.com if you are part of Apple ecosystem.

<comment><USER7> Doesn't sound like an open source alternative?

</comment></comment><comment><USER8> Wow Etherpad still exists?! That is OG YC.</comment>


Options for Moonlighting? - <AUTHOR> Hi Folks,
So I recently bought a house and I'm the only source of income. I crunched the numbers several times in a spreadsheet to make sure I should manage it. Even though I can manage it, I'd still like to make extra money preferably with programming since that's what I'm good at. If I could earn on average an extra $50-100 a week I'd be happy.
I've tutored in the past which isn't a great gig when you use services like Wyzant which take a 40% cut.
I've looked at contracting sites like guru, freelance, upwork but the jobs are vague and the bidding wars are intimidating.
I was thinking of keeping it local and offering shops and restaurants in my area my web design and programming services.
Does anyone have any thoughts or ideas? <comment><USER2> Why not find a startup that could use an extra developer, or an agency ? Restaurants, etc make horrible clients - and often pay very little, considering how much time it takes to close the deal. I could find moonlighting devs work all day. What technologies are you comfortable in?

<comment><AUTHOR> I'm very comfortable in SQL, Java, JavaScript (including jQuery), CSS, Clojure, Struts, Spring MVC and a little Android.

I do full-stack web app development for my day job and a lot of personal projects for fun.

<comment><USER2> Solid - please email me a resume or similar to chriszbond at gmail.com We can chat about moonlighting work - eg: a few hrs, a few hrs week, or a monht, etc.

I have immediate Java work (short but sweet, not a long project integrating into MySql and Kafka, and have JS FrontEnd/Backend Node.js that we could chat about.</comment></comment></comment>