[HN Gopher] Machine Code Isn't Scary
       ___________________________________________________________________
        
       Machine Code Isn't Scary
        
       Author : surprisetalk
       Score  : 194 points
       Date   : 2025-06-04 05:19 UTC (1 days ago)
        
 (HTM) web link (jimmyhmiller.com)
 (TXT) w3m dump (jimmyhmiller.com)
        
       | oleganza wrote:
       | Thank you Jimmy, great article.
       | 
       | My 23+ year experience in computer science and programming is a
       | zebra of black-or-white moments. For the most time, things are
       | mostly obscure, complicated, dark and daunting. Until suddenly
       | you stumble upon a person who can explain those in simple terms,
       | focus on important bits. You then can put this new knowledge into
       | a well-organized hierarchy in your head and suddenly become wiser
       | and empowered.
       | 
       | "Writing documentation", "talking at conferences", "chatting at a
       | cooler", "writing to a blog" and all the other discussions from
       | twitter to mailing lists - are all about trying to get some ideas
       | and understanding from one head into another, so more people can
       | get elucidated and build further.
       | 
       | And oh my how hard is that. We are lucky to sometimes have
       | enlightenment through great RTFMs.
        
       | amelius wrote:
       | Machine code was only "scary" in the old days when you had to
       | reboot your system when you made a small mistake.
        
         | rausr wrote:
         | I enjoyed having to reload everything from tape (compact
         | cassette tape - ie the kind of thing you'd use with a home
         | computer in the early eighties), after a crash due to my poor
         | code. I think the term used then was "character building" ;)
        
           | chopin wrote:
           | One of my first C programs wrote straight into the BIOS
           | memory (1989 iirc). The machine froze and refused to reboot.
           | We had to remove the BIOS battery to reset the BIOS. Luckily,
           | the battery wasn't soldered to the main board.
        
       | PlunderBunny wrote:
       | I taught myself to program on an 8-bit BBC micro-computer in the
       | mid-80s by typing in BASIC listings. I understood BASIC quite
       | well, and could write my own structured BASIC programs, but
       | machine code was always a bit out-of-reach. I would try to read
       | books that started by demonstrating how to add, subtract etc, but
       | I couldn't see how that could build up to more complicated stuff
       | that I could do in BASIC, like polling for input, or playing
       | sounds, or drawing characters on the screen. Only once I got an
       | advanced users guide and discovered the operating system
       | commands, then it started to click with me - the complicated
       | stuff was just arranging all the right data in the right bits of
       | memory or registers, then (essentially) calling a particular OS
       | command and saying 'here's the data you want'.
        
         | bowsamic wrote:
         | Yeah the issue is that the pedagogy doesn't make it clear how
         | to bridge the "calculator" with the OS stuff. I had this issue
         | when I was a kid. How does adding eventually make something
         | draw on the screen? Of course, it doesn't, you need some
         | hardware or OS specific information
        
           | eterm wrote:
           | It wasn't until I read Petzold's CODE that this stuff,
           | especially the role of the the motherboard bridging
           | processing, memory and I/O and what an OS is for, that it
           | started to click for me.
        
             | bowsamic wrote:
             | Yeah my stepdad bought me CODE as a kid and that really
             | helped. A similar book that took a "top down" approach as
             | much as possible would have also helped though, but would
             | be much harder to pull off
        
           | tux3 wrote:
           | But if this doesn't satisfy your curiosity, you might realize
           | this is just pushing the magic blackbox/question mark a
           | little further down the chain
           | 
           | How does the OS and the hardware draw on the screen,
           | actually? All they have is also just calculator stuff, super
           | basic primitives. You can't even do loops in hardware, or
           | even real branches (hardware always "executes both sides" of
           | a branch at once)
           | 
           | Anyways, if you keep digging long enough you eventually end
           | up finding this XKCD https://xkcd.com/435/ =)
        
             | tsimionescu wrote:
             | > hardware always "executes both sides" of a branch at once
             | 
             | Unless you're talking about quantum hardware, that is very
             | much not true. The whole point of transistors is to choose
             | whether to power one part of a circuit or another.
             | 
             | Plus, even for hardware, the solution to all this is to
             | modularize all the way down. One piece of hardware sets up
             | the right state and powers up another piece of hardware -
             | this type of logic doesn't stop at the OS level. For
             | drawing on the screen, ultimately you reach a piece of
             | hardware that lights up in one of three colors based on
             | that state - but all the way there, it's the same kind of
             | "function calls" (and even more indirection, such as
             | communication protocols) on many levels.
        
               | LegionMammal978 wrote:
               | At least for classic textbook CPUs, it's common to run
               | both sides of a decision in parallel while it's still
               | being made, then finally use a transistor to select the
               | desired result after the fact. No one wants the latency
               | of powering everything up and down every cycle, except on
               | the largest scales where power consumption makes a big
               | difference.
        
               | tsimionescu wrote:
               | I don't understand what you mean by decision. In a
               | textbook CPU, where there is no speculative execution and
               | no pipelining, the hardware runs one instruction at a
               | time, the one from the instruction pointer. If that
               | instruction is a conditional jump, this is a single
               | computation that sets the instruction pointer to a single
               | value (either next instruction or the specified jump
               | point). After the single new value of the instruction
               | pointer is computed, the process begins again - it
               | fetches one instruction from the memory address it finds
               | in the instruction point register, decodes it, and
               | executes it.
               | 
               | Even if you add pipelining, the basic textbook design
               | will stall the pipeline when it encounters a
               | conditional/computed jump instruction. Even if you add
               | basic speculative execution, you _still_ don 't get both
               | branches executed at once, necessarily - assuming you had
               | a single ALU, you'd still get only one branch executed at
               | once, and if the wrong one was predicted, you'll revert
               | and execute the other one once the conditional finishes
               | being computed.
        
               | LegionMammal978 wrote:
               | > I don't understand what you mean by decision.
               | 
               | I'm talking on a lower level than the clock cycle or
               | instruction. Let's say circuit A takes X and outputs
               | foo(X), and circuit B takes X and outputs bar(X). We want
               | to build a circuit that computes baz(X, Y) = Y ? foo(X) :
               | bar(X), where X is available before Y is. Instead of
               | letting Y settle, powering up one of the circuits A or B,
               | and sending X into it, we can instead send X to circuits
               | A and B at the same time, then use Y to select whichever
               | output we want.
        
               | tsimionescu wrote:
               | Agreed, we can do that, and it is done for many kinds of
               | circuits. But many others don't work like that, so it's
               | wrong to say that hardware works exclusively like this.
               | 
               | One other common pattern for implementing conditional
               | logic is to compute a boolean expression in which the
               | control signal is just another input variable. In that
               | model, to compute Y ? foo(X) : bar(X), we actually
               | compute baz(X, Y) whose result is the same. This is very
               | commonly how ALUs work.
               | 
               | And the other very common pattern is to split this in
               | multiple clock cycles and use registers for intermediate
               | results. If you _don 't_ have two circuits A and B, only
               | one circuit that can compute either A or B based on a
               | control signal (such as simple processors with a single
               | ALU), this is the only option: you take one clock cycle
               | to put Y in a register, and in the next clock cycle you
               | feed both Y and X into your single circuit which will now
               | compute either A or B.
        
               | MobiusHorizons wrote:
               | At least in CMOS, the power supplied to the transistor is
               | not being modulated as part of logic operations. Modern
               | hardware does clock gating and power gating of modules
               | for power saving, but that is not what the OP is talking
               | about.
               | 
               | In hardware the equivalent of a ternary is a mux, which
               | can be made from a lot of parallel instances of
               | out0 = (a0 & cond) | (b0 & ~cond)
               | 
               | Or in other words, both branches must be computed and the
               | correct value is chosen based on the condition.
        
               | tsimionescu wrote:
               | "Power" was very sloppy language on my side. I was
               | talking about the low voltage / high voltage difference
               | that you get from transistors. A logical gate ultimately
               | has a single output voltage based on its inputs. If its
               | inputs are 1 and 1 (+5V and +5V), its output will be,
               | say, 0 (0V), not "initially both 0 and 1, but later only
               | 1 is chosen".
               | 
               | Similarly, a two bit adder is not going to have all 4
               | possible states internally or for some time - as soon as
               | the input voltage is applied to its inputs, its output
               | voltages will correspond to the single result
               | (disregarding the analog signal propagation, which I
               | assume is not what you were talking about).
               | 
               | Similarly, a conditional jump instruction will not be
               | implented natively by computing both "branches". It will
               | do a single computation to set the instruction pointer to
               | the correct value (either current + 1 or destination).
               | Now sure, speculative execution is a different matter,
               | but that is extra hardware that was added late in the
               | processor design process.
        
               | MobiusHorizons wrote:
               | You can't really conditionally compute something in
               | hardware. The hard to do the computation exists and is
               | wired up always.
               | 
               | The conditional jump is a great example actually.
               | Typically this would be implemented by having one block
               | compute PC+<instruction size> and another block compute
               | the jump target and then choosing between the two using a
               | mux
        
               | tsimionescu wrote:
               | That is one way of implementing such conditionals in
               | hardware, but it's just one aspect of the computation.
               | First, we can both agree that in the next clock cycle, a
               | single instruction will be executed, not both
               | instructions that could result after the jump - so
               | clearly the hardware doesn't always do both things.
               | 
               | Secondly, if we think about the instruction decoding
               | itself, it should become pretty clear that even if the
               | hardware of course always exists and is always going to
               | output something, that's not equivalent to saying it will
               | compute all options. If the next instruction is `add ax,
               | bx`, the hardware is not going to compute both ax + bx
               | and ax - bx and ax & bx and ax | bx and so on, and then
               | choose which result to feed back to ax through a mux.
               | Instead, the ALU is constructed of logic gates which
               | evaluate a single logical expression that assigns each
               | output bit to a logical combination of the input bits and
               | the control signal.
        
       | shakna wrote:
       | I started building a Forth recently, but decided that instead of
       | interpreter or transpiler or whatever, I'd map to bytes in memory
       | and just straight execute them.
       | 
       | This non-optimising JIT has been far, far easier than all the
       | scary articles and comments I've seen led me to believe.
       | 
       | I'm already in the middle of making it work on both Aarch64 and
       | RISC-V, a couple weeks in.
        
         | simpleui wrote:
         | Very interesting, care to share the source?
        
           | shakna wrote:
           | Oh, it's still a while off that. I do plan to make it public
           | at some point, but when I'm actually happy the code isn't
           | completely vomit.
           | 
           | But for a simple taste, the push to stack function currently
           | looks like this. (All the emit stuff just writes bytes into a
           | mmap that gets executed later.)                   void
           | compile_push_literal(Value val) {         #if ARCH_X86_64
           | emit_bytes((uint8_t[]){X86_MOV_RDI_IMM64_0,
           | X86_MOV_RDI_IMM64_1}, 2); emit_uint64_le(val);
           | emit_bytes((uint8_t[]){X86_MOV_RAX_IMM64_0,
           | X86_MOV_RAX_IMM64_1}, 2); emit_uint64_le((uint64_t)push);
           | emit_bytes((uint8_t[]){X86_CALL_RAX_0, X86_CALL_RAX_1}, 2);
           | #elif ARCH_ARM64             uint64_t imm = val;
           | emit_uint32_le(ARM64_MOVZ_OP | (ARM64_REG_X0 << 0) | ((imm &
           | 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL16 | (ARM64_REG_X0 << 0) |
           | (((imm >> 16) & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL32 | (ARM64_REG_X0 << 0) |
           | (((imm >> 32) & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL48 | (ARM64_REG_X0 << 0) |
           | (((imm >> 48) & 0xFFFF) << 5));             uint64_t
           | func_addr = (uint64_t)push;
           | emit_uint32_le(ARM64_MOVZ_OP | (ARM64_REG_X1 << 0) |
           | ((func_addr & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL16 | (ARM64_REG_X1 << 0) |
           | (((func_addr >> 16) & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL32 | (ARM64_REG_X1 << 0) |
           | (((func_addr >> 32) & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_MOVK_OP_LSL48 | (ARM64_REG_X1 << 0) |
           | (((func_addr >> 48) & 0xFFFF) << 5));
           | emit_uint32_le(ARM64_BLR_OP | (ARM64_REG_X1 << 5));
           | #elif ARCH_RISCV64             emit_load_imm_riscv(val,
           | RISCV_REG_A0, RISCV_REG_T1);
           | emit_load_imm_riscv((uint64_t)push, RISCV_REG_T0,
           | RISCV_REG_T1);             emit_uint32_le((0 << 20) |
           | (RISCV_REG_T0 << 15) | (RISCV_F3_JALR << 12) | (RISCV_REG_RA
           | << 7) | RISCV_OP_JALR);         #endif         }
        
             | User23 wrote:
             | This is super cool!
             | 
             | Creating an assembler with Lisp syntax and then using that
             | to bootstrap a Lisp compiler (with Lisp macros instead of
             | standard assembler macros) is one of those otherwise
             | pointless educational projects I've been wanting to do for
             | years. One day perhaps.
        
               | pjmlp wrote:
               | Even though I tend to be a bit negative into the whole
               | WebAssembly hype, that is exactly a good starting point.
               | 
               | You already have the assembler with Lisp syntax covered.
               | 
               | Add some macro support on top, and you can start already
               | implementing the upper layer for your Lisp.
               | 
               | Naturally there are already a couple of attempts at that.
        
             | simpleui wrote:
             | Thanks Shakna!
        
             | 0x000xca0xfe wrote:
             | Machine code generation for RISC-V is so easy. Excellent
             | for teaching.
        
         | cnity wrote:
         | I did this for WebAssembly WAT (an IR that is syntactically
         | similar to lisp) by mapping the AST for my lisp more or less
         | directly to the WAT IR, then emitting the bytecode from there.
         | It was pretty fun.
        
         | pjmlp wrote:
         | We did a similar approach back in the day, when going through
         | the Tiger language[0], on the Java version.
         | 
         | Our approach was to model the compiler IR into Assembly macros,
         | and follow the classical UNIX compiler build pipeline, thus
         | even though it wasn't the most performant compiler in the
         | world, we could nonetheless enjoy having our toy compiler
         | generate real executables in the end.
         | 
         | [0] - https://www.cs.princeton.edu/~appel/modern
        
         | mananaysiempre wrote:
         | I mean, it's not hard as such, the encodings of some
         | instruction sets are just ass, with 32- and 64-bit x86 as the
         | foremost example and Thumb-2 not far behind it. Also, if you're
         | dynamically patching existing code, you'll have to contend with
         | both modern OSes (especially "hardening" patches thereto)
         | making your life harder in bespoke incompatible ways (see: most
         | of libffi) and modern CPUs being very buggy around self-
         | modifying code. Other than that, it just takes quite a bit of
         | tedious but straightforward work to get anywhere.
        
           | shakna wrote:
           | I haven't had any issues with the OS.
           | 
           | I mmap, insert, mark as executable and done. Patchjumping and
           | everything "just works".
           | 
           | I'm not modifying my own process, so there's no hardening
           | issues. Just modifying an anonymous memory map.
        
       | davemp wrote:
       | When I was last working with machine code, I found capstone to be
       | very useful. Even just reading the source was helpful for some of
       | the conditionally present amd64 fields.
       | 
       | https://github.com/capstone-engine/capstone
        
       | jmclnx wrote:
       | That is one thing that was nice about DOS, you where close to the
       | machine. I never fully got machine language, but it was fun
       | trying.
       | 
       | IIRC, debug.com could be used to create programs using machine
       | lang.
        
         | pjmlp wrote:
         | Yes, it was a quite bare bones experience when compared to TASM
         | and MASM, and only worked for COM executable, but it did work.
         | 
         | The reasoning being that COM files were a plain memory dump
         | starting at offset 100H, thus you would type the code in memory
         | and then dump it.
        
       | dedicate wrote:
       | For me the 'scary' part of machine code was never the actual
       | logic. It was always just staring at that wall of hex or
       | mnemonics and feeling like I needed a secret decoder ring!
        
         | jiehong wrote:
         | Yes, that does not help.
         | 
         | To me, it looks like some kind of complex tetris game. I guess
         | we could maybe represent a program as such, with pieces for
         | registers, instructions, etc.
         | 
         | Yet, the tooling we have is very terse, and textual.
        
       | Lerc wrote:
       | I have tried to convince people that ASM is reasonable as a first
       | stage teaching language. The reputation as a nearly mystical art
       | practiced by a few doesn't help. The thing is, instructions are
       | simple. Getting them to do things is not hard, the difficulty
       | comes from tasks exceeding a scale where you can think about
       | things at their most basic level.
       | 
       | It quickly becomes tedious to do large programs, not really hard,
       | just unmanagable, which is precisely it should be taught as a
       | first language. You learn how do do simple things and you learn
       | why programming languages are used. You teach the problem that is
       | being solved before teaching more advanced programming concepts
       | that solve the problem.
        
         | flohofwoe wrote:
         | IMO It depends a lot on the assembly flavour.
         | 
         | The best ISA for learning is probably the Motorola 68000,
         | followed by some 8-bit CPUs (6502, 6809, Z80), also probably
         | ARM1, although I never had to deal with it. I always thought
         | that x86 assembly is ugly (no matter if Intel or AT&T).
         | 
         | > It quickly becomes tedious to do large programs
         | 
         | IME with modern tooling, assembly coding can be surprisingly
         | productive. For instance I wrote a VSCode extension for 8-bit
         | home computers [1], and dog-fooded a little demo with it [2],
         | and that felt a lot more productive than back in the day with
         | an on-device assembler (or even typing in machine code by
         | numbers).
         | 
         | [1]
         | https://marketplace.visualstudio.com/items?itemName=floooh.v...
         | 
         | [2] https://floooh.github.io/kcide-
         | sample/kc854.html?file=demo.k...
        
           | whobre wrote:
           | I agree that M68k is nice, as are the 8-bit ones you mention.
           | I just find it strange that you like Z80 and dislike x86 -
           | they are fundamentally not that different and both are
           | descended from 8080.
        
             | flohofwoe wrote:
             | Yeah the Z80 instruction set is quite messy (mainly because
             | it had to fill gaps of the 8080 instruction set for
             | backward compatibility). But as an evolution of the 8080
             | instruction set, the Z80 is still cleaner than x86 (IMHO!).
             | 
             | Also, the Z8000 looks quite interesting and like the better
             | 16-bit alternative to the x86, but it never took off:
             | https://en.wikipedia.org/wiki/Zilog_Z8000
        
           | tsimionescu wrote:
           | Sure, but learning an old ISA can leave you with a very very
           | wrong idea about how modern processors work. Even x86
           | assembly paints a very misleading image of how modern
           | processors actually work. For example, someone learning
           | x86-64 assembly will likely believe all of the following:
           | 
           | - assembly instructions are executed in the order they appear
           | in in the source code
           | 
           | - an x86 processor only has a handful of registers
           | 
           | - writing to a register is an instruction like any other and
           | will take roughly the same time
           | 
           | - the largest registers on an x86 processor are 64-bit
        
             | t-3 wrote:
             | They will be disabused of any of those notions simply by
             | reading the relevant portions of the architecture handbook.
             | In a pedagogical environment that's very simple to arrange.
        
               | tsimionescu wrote:
               | Someone who is just learning to program will _not_ be
               | well served by reading a modern CPU architecture
               | handbook. It is far too complex for someone who doesn 't
               | even know yet what a graph is, for example.
        
             | flohofwoe wrote:
             | Peeking under the hood is a later step after getting
             | comfortable with assembly coding. E.g. none of those
             | details are really relevant when starting out, instead it
             | makes a lot of sense to do a speed run through computing
             | history in order to really understand why modern CPUs (and
             | computers as a whole) work like they do.
        
             | ThrowawayR2 wrote:
             | All of which are completely irrelevant implementation
             | details hidden behind the ISA. The x86-64 ISA promises
             | execution of instructions in the specified order, a certain
             | number of registers, etc. and that's all they need to know.
        
               | Someone wrote:
               | > The x86-64 ISA promises execution of instructions in
               | the specified order
               | 
               | It doesn't, and out-of-order CPUs don't do that.
               | https://en.wikipedia.org/wiki/Out-of-order_execution:
               | _"In this paradigm, a processor executes instructions in
               | an order governed by the availability of input data and
               | execution units, rather than by their original order in a
               | program."_
        
               | flohofwoe wrote:
               | Out-of-order execution is an internal optimization, from
               | the outside results are still guaranteed to be available
               | in order - e.g. the instruction stream _appears_ to be
               | executed in order when observing the CPU from the
               | outside.
               | 
               | For instance you don't need to be afraid that an
               | instruction uses garbage inputs just because a previous
               | instruction hadn't finished computing an input value to
               | the instruction. At worst you'll get a pipeline stall if
               | the CPU can't fill the gap with out-of-order executed
               | instructions.
               | 
               | On some CPUs it _does_ get tricky once memory is involved
               | though (on ARM, but not on x86).
        
               | Someone wrote:
               | > from the outside results are still guaranteed to be
               | available in order - e.g. the instruction stream appears
               | to be executed in order when observing the CPU from the
               | outside.
               | 
               | > [...]
               | 
               | > On some CPUs it does get tricky once memory is involved
               | though (on ARM, but not on x86).
               | 
               | https://en.wikipedia.org/wiki/Memory_ordering:
               | 
               |  _"Among the commonly used architectures, x86-64
               | processors have the strongest memory order, but may still
               | defer memory store instructions until after memory load
               | instructions."_
        
               | ThrowawayR2 wrote:
               | I explicitly said ISA for a reason: https://en.wikipedia.
               | org/wiki/Instruction_set_architecture. OoO is not exposed
               | at the ISA level.
        
               | tsimionescu wrote:
               | The claim is that learning assembler first will build a
               | better intuition about the inner workings, and thus
               | performance, of the processor.
               | 
               | The reality is that any assembler simple enough to be
               | taught as your first contact with programming will leave
               | you with a _wrong_ intuition about how modern processors
               | work, and thus a wrong intuition about the relative
               | performance of various operations.
               | 
               | Having no intuition about something is better than
               | building a bad intuition, especially at the beginning of
               | your learning journey.
        
           | Lerc wrote:
           | Oh nice, I was talking just yesterday how I liked chips as a
           | programming paradigm.
           | 
           | I agree about tooling, I made a pacman game in a dcpu16
           | emulator in a couple of days.
           | https://fingswotidun.com/dcpu16/pac.html
           | 
           | I experimented with a fantasy console idea using an in-
           | browser assembler as well.
           | https://k8.fingswotidun.com/static/ide/
           | 
           | I think you can build environments that give immediate
           | feedback and the ability to do real things quickly in ASM. I
           | would still recommend moving swiftly on to something higher
           | level as soon as it started to feel like a grind.
        
         | criddell wrote:
         | If you have a good macro assembler, it is only a little more
         | difficult than C. There's just more to learn up front (things
         | like calling conventions, register usage, etc...).
         | 
         | I wouldn't teach it first, but after a person knows the basics
         | in another language, seeing how it all actually works can be
         | fun.
        
         | tsimionescu wrote:
         | The biggest problem with using ASM as a first language to teach
         | beginners is that it is extremely tedious, error prone, and
         | sensitive to details. It is also unstructured, it uses entirely
         | different control flow primitives than any language they will
         | learn in the future, meaning they will not be well prepared for
         | learning a real language that does scale to programs more
         | complex than a few additions and calling an OS output routine.
         | 
         | So why teach someone a language that doesn't have if, while,
         | (local) variables, scopes, types, nor even real function calls?
         | 
         | It's a very nice exercise for understanding how a computer
         | functions, and it has a clear role in education - I'm not
         | arguing people shouldn't learn it at all. But I think it's a
         | terrible first language to learn.
        
           | yetihehe wrote:
           | > So why teach someone a language that doesn't have if,
           | while, (local) variables, scopes, types, nor even real
           | function calls?
           | 
           | You can teach them how to implement function calls, variables
           | and loops using assembly, to show them how they work under
           | the hood and how they should be thankful for having simple if
           | in their high level languages like C.
        
             | tsimionescu wrote:
             | That often leaves people with very bad mental models of how
             | programs actually compile in modern optimizing compilers
             | and in modern operating systems (e.g. people end up
             | believing that variables always live on the stack, that
             | function parameters are passed on the stack, that loops are
             | executed in the same way regardless of how you write them,
             | etc).
        
               | dmwilcox wrote:
               | Think about how far they've come if you get them to have
               | these "misconceived" ideas!
               | 
               | They would understand code and data are in the same
               | place, that all flow control effectively boils down to a
               | jump, and they have a _more_ accurate picture of the
               | inside of a machine than anyone starting out with Python
               | or JavaScript could hope for.
               | 
               | Having spent 25 years to get to assembler, I wish I'd
               | started it sooner. It's truly a lovely way to look at the
               | machine. I'll definitely be teaching my kids how to
               | program in assembly first (probably x86-16 using DOS as a
               | program launcher)
        
               | horsawlarway wrote:
               | They have to want to understand any of those things
               | first.
               | 
               | Be very careful that you're not going to just kill
               | enthusiasm for programming as an activity entirely with
               | this approach.
               | 
               | I see this happen a lot (I did a lot of
               | robotics/programming mentoring), and then adults wonder
               | why their kids don't like any of the stuff they like -
               | and the reason is that the adult was really a dick about
               | making them learn the things the adult liked, and ignored
               | most of the fun aspects of the activity, or the wishes of
               | the kid.
        
               | zahlman wrote:
               | > and then adults wonder why their kids don't like any of
               | the stuff they like - and the reason is that the adult
               | was really a dick about making them learn the things the
               | adult liked
               | 
               | This can be done with any programming language.
               | 
               | The point of teaching assembly isn't for someone to
               | memorize all the details of any particular instruction
               | set. It's about conceiving of the decomposition of
               | problems on that level. It's about understanding _what
               | data is_ , so that when the student later learns a
               | higher-level programming language, it sets expectations
               | for what happens when you open a file, what kind of
               | processing has to be done, etc. It's the basis for
               | understanding abstractions that are built upon all those
               | 1s and 0s, about the way that a program implicitly
               | assigns semantics to them.
               | 
               | (This is best done with a toy assembly language, not one
               | that comes anywhere near reflecting the complexity of
               | modern CPUs. Anything to do with the practical
               | considerations of modern optimizing compilers is also
               | missing the point by a mile.)
        
               | horsawlarway wrote:
               | > It's about conceiving of the decomposition of problems
               | on that level. It's about understanding what data is, so
               | that when the student later learns a higher-level
               | programming language, it sets expectations for what
               | happens when you open a file, what kind of processing has
               | to be done, etc. It's the basis for understanding
               | abstractions that are built upon all those 1s and 0s,
               | about the way that a program implicitly assigns semantics
               | to them.
               | 
               | These are all things that are _your_ goals, as the adult
               | and teacher.
               | 
               | The student who wants to engage with programming and
               | software likely has other goals in mind.
               | 
               | Skip all the crap you just mentioned, focus on helping
               | them achieve their goals. I think you'll find those are
               | usually more in the realm of "I want to make a game" or
               | "I want to show my stuff to friends on a website" or "I
               | want to make the computer play music" or [insert other
               | high level objective that's not "learn about bits and
               | bytes"].
               | 
               | Will that involve the stuff you mentioned? Sure will, and
               | a student who feels like they're achieving the thing they
               | want by learning that stuff is engaged.
               | 
               | But a student who gets to just sit there and listen to
               | you drone on and on about "abstractions" and
               | "instructions sets" and "data is code" and "semantics"
               | all to end up with a complicated file that functionally
               | just adds two numbers together? That student is usually
               | bored and disengaged.
        
               | zahlman wrote:
               | > The student who wants to engage with programming and
               | software likely has other goals in mind.
               | 
               | And the student who doesn't learn these concepts _will
               | inevitably_ run into a roadblock soon thereafter.
               | 
               | > But a student who gets to just sit there and listen to
               | you drone on and on about "abstractions" and
               | "instructions sets" and "data is code" and "semantics"
               | 
               | You don't "drone on" about these things. You introduce
               | them as it makes sense, by pointing things out about the
               | first programs as they are developed. You don't _talk
               | about_ abstracting things and assigning semantics; you
               | _do it_ , and then point out what you've done.
        
               | horsawlarway wrote:
               | > You introduce them as it makes sense
               | 
               | So we agree that maybe dragging them right into the start
               | by teaching assembly (because it's good at teaching those
               | things) as the first time language isn't the best
               | strategy?
               | 
               | At no point will I argue against learning it. Knowing how
               | machines work is great, and I think going "down" the
               | stack benefits a lot of developers _ONCE_ they 're
               | developers and have an understanding that programming and
               | computers are things they like and want to do.
               | 
               | But first you have to foster enthusiasm and nurture
               | interest. You don't do that by declaring that you're
               | going to teach your kids assembly... you do that by
               | listening to your kids interests in the space and helping
               | them achieve _their_ goals.
        
               | Pet_Ant wrote:
               | They will then run into a roadblock when they've already
               | done something fun and are invested in the project.
               | 
               | Reading is easier when you know your latin roots, but we
               | don't make kids speak latin before See Spot Run even if
               | it would help.
        
               | zahlman wrote:
               | > and they have a _more_ accurate picture of the inside
               | of a machine than anyone starting out with Python or
               | JavaScript could hope for.
               | 
               | Frankly, a more accurate picture than those starting in C
               | have, too.
        
               | t-3 wrote:
               | After learning asm, teach compilers and have them think
               | about how to generate code stupidly, then think about how
               | to generate efficient code. If you don't want people
               | thinking about the stack, just teach them RISC rather
               | than x86.
        
               | tsimionescu wrote:
               | So you think people should start their programming
               | journey by writing a compiler in assembly? What exactly
               | should it compile, if they haven't learned any other
               | language?
        
               | t-3 wrote:
               | It's relatively common is university CS courses to build
               | a compiler after the basic intro and architecture
               | courses. It's one of the simpler projects (yes, really,
               | compilers are rather simple, optimization is the hard
               | part) that involves a lot high-level concepts and exposes
               | a lot of the thought behind things otherwise obscure. A
               | compiler for a simple 4-function calculator is enough to
               | start with, then higher-level constructs can be added
               | easily while introducing them.
        
               | tsimionescu wrote:
               | In my university, compilers were a third-year course. And
               | they're anything but simple - even the most well solved
               | part of them, parsing, used to be a research-level
               | problem until fairly recently. To build even a simple
               | non-optimizing compiler you have to understand a whole
               | lot of other fundamentals, such as various data
               | structures, that are much, much harder to understand in
               | assembler then in any higher level language, even C.
        
               | bitwize wrote:
               | But if they know assembly, they can look at actual
               | compiler output and form the correct mental models...
        
           | diggan wrote:
           | > it is extremely tedious, error prone, and sensitive to
           | details.
           | 
           | That sounds like the perfect beginner language! If they
           | survive that experience, they'll do very well in almost any
           | type of programming, as it's mostly the same just a tiny bit
           | less tedious. A bit like "hardening" but for programmers.
        
             | HeyLaughingBoy wrote:
             | Perhaps if you want to gatekeep for the most stubborn
             | individuals, but you'll lose a lot of talent that way.
        
               | diggan wrote:
               | Isn't programming already mostly for the most stubborn
               | individuals? I don't know many non-programmers who would
               | willingly bang their head against the same problem for
               | days, especially when in front of a computer.
               | 
               | I guess it's as much "gatekeeping" as being required to
               | formulate plans and balance tradeoffs is "gatekeeping".
        
           | horsawlarway wrote:
           | So much this.
           | 
           | This is like learning to read by first being asked to
           | memorize all the rules of grammar and being quizzed on them,
           | or being forced to learn all the ins and outs of book binding
           | and ink production.
           | 
           | It's tedious, unproductive, miserable.
           | 
           | There's very little reward for a lot of complexity, and the
           | complexity isn't the "stimulating" complexity of thinking
           | through a problem; it's complexity in the sense of "I put the
           | wrong bit in the wrong spot and everything is broken with
           | very little guidance on why, and I don't have the mental
           | model to even understand".
           | 
           | There's a perfectly fine time to learn assembly and machine
           | instructions, and they're useful skills to have - but they
           | really don't need to be present at the beginning of the
           | learning process.
           | 
           | ---
           | 
           | My suggestion is to go even farther the other way. Start at
           | the "I can make a real thing happen in the real world with
           | code" stage as soon as possible.
           | 
           | Kids & adults both light up when they realize they can make
           | motor turn, or an LED blink with code.
           | 
           | It's similarly "low level" in that there isn't much going on
           | and they'll end up learning more about computers as machines,
           | but much more satisfying and rewarding.
        
             | skydhash wrote:
             | The best way to go about that is to use a simulator for an
             | old cpu like EdSim51[0]. Can do a lot of things with just a
             | few lines of code.
             | 
             | > _it 's complexity in the sense of "I put the wrong bit in
             | the wrong spot and everything is broken with very little
             | guidance on why, and I don't have the mental model to even
             | understand_
             | 
             | That's the nice thing about assembly, it always works, but
             | the result may not be as expected. But instead of having a
             | whole lot of magic between what is happening and how you
             | model it, it's easy to reason about the program. You don't
             | have to deal with stack trace, types, garbage collection
             | and null pointer exception. Execution and programming is
             | the same mental model, linear unless you said so.
             | 
             | You can start with assembly and then switch to C or Python
             | and tell them: For bigger project, assembly is tedious and
             | this is what we invented instead.
             | 
             | [0]: https://edsim51.com/about-the-simulator/
        
               | tsimionescu wrote:
               | No, assembly doesn't "always work". It almost always does
               | _something_ , true, which is the worse thing about it:
               | instead of getting some error, you get to figure out why
               | the value at the end of your program is not the value you
               | expected, and which of the hundred instructions before
               | that caused it to be wrong.
        
               | homebrewer wrote:
               | I vote for microcontrollers. I learned assembly on
               | Atmel's AVR and it's was easy and straightforward because
               | there's very little abstraction underneath, there's no
               | OS, no heap, no multiprocessing and no context switching,
               | no syscalls and no fat libraries, and you get direct
               | access to the hardware. You also receive actual physical
               | feedback -- doing a tiny bit of bit fiddling gets you a
               | blinking LED or whatever.
               | 
               | AVR's assembly is quite mediocre, with 120+ something
               | instructions, with lots of duplication among them (IIRC
               | -- it's been... many years already), and some people
               | swore by PIC which only had 35 instructions to remember.
               | But it was still easier than lobotomizing oneself by
               | trying to write a Win32 application in x86 assembly
               | (which came later... and went to the trash bin quickly
               | while microcontrollers stuck for much longer).
        
           | MobiusHorizons wrote:
           | Because these are the primatives that are in use when
           | programming in any language, and there is a benefit to
           | learning the primatives before learning higher level
           | abstractions. For instance we teach arithmetic before
           | calculus.
           | 
           | I see lots of people become pretty helpless when their
           | framework isn't working as expected or abstraction becomes
           | leaky. Most people don't really need to know assembly in
           | order to get past this, but the general intuition of "there
           | is something underneath the subtraction that I could
           | understand" is very useful.
        
             | jader201 wrote:
             | _> For instance we teach arithmetic before calculus._
             | 
             | I don't think that's a fitting analogy.
             | 
             | Nearly everyone on the planet uses (basic) arithmetic. Very
             | few use calculus.
             | 
             | By contrast, very few (programmers) use ASM, but nearly all
             | of them use higher level languages.
        
               | nightski wrote:
               | I'd say every programmer uses the constructs in assembly.
               | Just because we have layers and layers of abstraction on
               | top of that doesn't mean it's not valuable to understand
               | the far simpler world that it all sits upon (Granted I
               | understand it sits upon machine code, not assembly, but
               | assembly is probably the closest to machine code that is
               | more human interpret-able without significant effort).
               | 
               | My first language was BASIC on a V-tech. It's not quite
               | the same but it still was such a fantastic starting
               | point.
               | 
               | I've tried luring people into programming with Python for
               | example and see them get frustrated by the amount of
               | abstractions and indirection going on. I am really
               | starting to like this idea of starting with assembly.
        
               | jader201 wrote:
               | Yeah, my point wasn't that learning ASM isn't valuable,
               | or that we don't use the constructs in higher level
               | languages.
               | 
               | My point is that the analogy with arithmetic vs. calculus
               | doesn't hold.
               | 
               | Nearly everyone uses basic arithmetic in everyday life,
               | and a tiny fraction of those use calculus.
               | 
               | No programmer _needs_ to learn ASM to be able to know how
               | to use higher level languages. And a tiny fraction of
               | them are using actual ASM in their everyday jobs.
               | 
               | Also, I think you can still learn the basic constructs of
               | how languages work at a lower level without every
               | learning actual ASM. There's no way you can learn
               | calculus without an understanding of arithmetic.
        
               | wat10000 wrote:
               | Most people don't use basic arithmetic in everyday life
               | anymore. They use machines which use arithmetic. Just
               | like most programmers don't use assembly, they use
               | programs which use assembly. In both cases, understanding
               | what's going on is very useful even if you aren't
               | directly touching that layer yourself.
        
               | tsimionescu wrote:
               | By this token, everyone who counts apples in a market is
               | using the axioms of Peano arithmetic every day.
               | 
               | The fact that our high level languages compile down to
               | assembly doesn't mean we _use_ assembly in any meaningful
               | sense. My C code will be correct or not based on whether
               | it conforms to the semantics of the C abstract machine,
               | regardless of whether those semantics match the semantics
               | of the assembly language that it happens to compile down
               | to. Even worse, code that is perfectly valid in assembler
               | may be invalid C, _even if the C code compiles down to
               | that same assembler code_. The most clear example is
               | adding 1 to an int variable that happens to have the
               | value MAX_INT. This code will often compile down to
               | "add, ax, 1" and set the variable to MIN_INT, but it is
               | nevertheless invalid C code and the compiler will assume
               | this value is impossible to happen.
               | 
               | This relationship between a programming language and
               | assembler is even more tenuous for languages designed to
               | run on heavy runtimes, like Java or JavaScript.
        
             | jcranmer wrote:
             | The primitives of control flow in programming languages are
             | sequencing, if, while, for, switch, return, and "early
             | return" (goto restricted to exit a containing block). We
             | might compile these into a form that represents everything
             | using conditional jumps, unconditional jumps, and jump
             | tables, but that's not how people think about it,
             | definitely not at the level of programming languages (and
             | even in the compiler IR phase, we're often mentally
             | retranslating the conditional jump/unconditional jump model
             | _back_ into the high-level control flows).
             | 
             | And I could go on with other topics. High-level languages,
             | even something like C, are just a completely different
             | model of looking at the world from machine language, and
             | truly understanding how machines work is actually quite an
             | alien model. There's a reason that people try to pretend
             | that C is portable assembler rather than actually trying to
             | work with a true portable assembler language.
             | 
             | The relationship you're looking for is not arithmetic to
             | calculus, but set theory to arithmetic. Yes, you can build
             | the axioms of arithmetic on top of set theory as a purer
             | basis. But people don't think about arithmetic in terms of
             | set theory, and we _certainly_ don 't try to teach set
             | theory before arithmetic.
        
             | tsimionescu wrote:
             | I think comparing assembly with arithmetic is dead wrong.
             | Arithmetic is something that you use constantly in
             | virtually any mathematical activity you will ever do, at
             | least at the under-graduate level. There is literally 0
             | calculus, statistics, or algebra you could understand if
             | you didn't know arithmetic.
             | 
             | In contrast, you can have a very successful, very advanced
             | career in computer science or in programming without once
             | in your life touching a line of assembler code. It's not
             | very likely, and you'll be all the poorer for it, but it's
             | certainly possible.
             | 
             | Assembly language is much more like learning the
             | foundations of mathematics, like Hilbert's program (except,
             | of course, historically that came a few millenia after).
        
           | flohofwoe wrote:
           | Starting with assembly makes it pretty clear _why_ higher
           | level languages had been invented. E.g. a speed run through
           | computing:
           | 
           | - machine code
           | 
           | - assembly
           | 
           | - Lisp and Forth
           | 
           | - C
           | 
           | - Pascal
           | 
           | - maybe a short detour into OOP and functional languages
           | 
           | ...but in the end, all you need to understand for programming
           | computers are "sequences, conditions and loops" (that's what
           | my computer club teacher used to say - still good advice).
        
             | tsimionescu wrote:
             | > but in the end, all you need to understand for
             | programming computers are "sequences, conditions and loops"
             | 
             | I fully agree - and assembly language teaches you precisely
             | 0 of these.
        
               | flohofwoe wrote:
               | Well, Z80 has DJNZ which is specifically designed for
               | loops ;)
               | 
               | I think there's value in understanding how high level
               | language constructs like if-else and loops can all be
               | constructed from simple conditional jumps, and that a
               | function call is just a CALL/RET pair with the return
               | address being stored on the stack.
               | 
               | Also, structured programming had to be invented, and
               | working in assembly code makes it clearer why.
               | 
               | It's also food for thought why CPU ISAs never made the
               | leap to structured programming.
        
               | tsimionescu wrote:
               | Various assembly languages have various exotic features.
               | I didn't even get into discussing which particular
               | assembly we may want to talk about. Still, DJNZ is still
               | a conditional jump, not a loop. You tell it where to jump
               | if some counter is not yet 0, you don't tell it which
               | instructions to repeat. The two are of course isomorphic
               | concepts, but still different.
               | 
               | And I absolutely agree there is value in understanding
               | the mechanics of how languages are executed. What I
               | disagree with is that this is necessary for being a good
               | programmer, and that it is useful as an initial learning
               | experience.
               | 
               | Programming itself didn't start with assembly. It started
               | with pseudo-code, which was always expressed in a high-
               | level format, and then manually translated to some form
               | of assembly language for a particular physical machine.
               | But people have never designed their programs in terms of
               | assembly - they have always designed them in higher level
               | terms.
        
             | TheOtherHobbes wrote:
             | I'd change the end of that list to C, Pascal, Lisp, Python.
             | 
             | But in the end no one learns "assembler". Everyone learns a
             | specific ISA, and they all have different strengths and
             | limitations. Assembler on a 36-bit PDP-10, with 16
             | registers and native floating point, is a completely
             | different experience to assembler on a Z80 with an 8-bit
             | accumulator and no multiply or divide.
             | 
             | You can learn about the heap and the stack and registers
             | and branches and jumps on both, but you're still thinking
             | in terms of toy matchstick architecture, not modern
             | building design.
        
           | wang_li wrote:
           | We teach math this way. Addition and subtraction. Then
           | multiplication. Then division. Fractions. Once those are
           | understood we start diversifying and teaching different
           | techniques where these make up the building blocks,
           | statistics, finance, algebra, etc.
           | 
           | It may put people off a programming career, but perhaps that
           | is good. There are a lot of people who work in programming
           | who don't understand the machines they use, who don't
           | understand algorithms and data structures, they have no idea
           | of the impact of latency, of memory use, etc. They're entire
           | career is predicated on being able to never have to solve a
           | problem that hasn't been solved in general terms already.
        
             | tsimionescu wrote:
             | We teach math starting with basic arithmetic, starting from
             | the middle. We don't go explaining what numbers are in
             | terms of sets, we don't teach Peano arithmetic or other
             | theories that can give logical definitions of arithmetic
             | from the ground up.
             | 
             | Plus, it is literally impossible to do any kind of math
             | without knowing arithmetic. It is very possible to build a
             | modestly advanced career knowing no assembly language.
        
             | 9rx wrote:
             | _> We teach math this way. Addition and subtraction. Then
             | multiplication. Then division_
             | 
             | The first graders in my neighbourhood school are currently
             | leaning about probability. While they did cover addition
             | earlier in the year, they have not yet delved into topics
             | like multiplication, fractions, or anything of that sort.
             | What you suggest is how things were back in my day, to be
             | fair, but it is no longer the case.
        
           | wavemode wrote:
           | > extremely tedious, error prone, and sensitive to details
           | 
           | I've taught people Python as their first language, and this
           | was their exact opinion of it.
           | 
           | When you're an experienced programmer you tend to have a poor
           | gauge of how newcomers internalize things. For people who are
           | brand new it is basically all noise. We're just trying to
           | gradually get them used to the noise. Getting used to the
           | noise while also trying to figure out the difference between
           | strings, numbers, booleans, lists, etc. is more difficult for
           | newcomers than many people realize. Even the concept of
           | scoping can sometimes be too high-level for a beginner, IME.
           | 
           | I like asm from the perspective that, its semantics are
           | extremely simple to explain. And JMP (GOTO) maps cleanly from
           | the flowchart model of programming that most people intuit
           | first.
        
             | cameldrv wrote:
             | IMO Python used to be a great first language, but it's
             | gotten much more complicated over the years. When I'm
             | teaching programming, I want an absolute minimum number of
             | things where I have to say "don't worry about that, it's
             | just boilerplate, you'll learn what it means later."
             | 
             | In particular, Python having generators and making range()
             | be a generator means that in order to fully explain a
             | simple for loop that's supposed to do something X times, I
             | have to explain generators, which are conceptually
             | complicated. When range() just returned a list, it was much
             | easier to explain that it was iterating over a list that I
             | could actually see.
        
               | ziml77 wrote:
               | It's probably best to act like more complex things are
               | just syntax at the start. Leave the fact that something
               | like range is just a normal function that returns a
               | generator for later on.
               | 
               | Like if range was used like this:                   for i
               | in range 1 to 100:             pass
               | 
               | No one is going to ask how that works internally, so I
               | don't think it's necessary to treat range(1, 100) any
               | differently. For this usage it makes no difference if
               | it's a generator, a list (excepting performance on large
               | ranges), or if the local variable is incremented directly
               | like a C-style for loop.
        
               | pjmlp wrote:
               | Python has made it into my toolbox around version 1.6.
               | 
               | It was already much more powerful than most people
               | writing simple shell script replacements were aware of.
               | 
               | Thing is, very few bother to read the reference manuals
               | cover to cover.
        
             | wat10000 wrote:
             | My kid is just finishing up a high school intro CS class. A
             | full school year in, and they _still_ have trouble with the
             | fact that their variable and type names must have the exact
             | same capitalization everywhere they 're used.
        
             | tsimionescu wrote:
             | I do realize how difficult this all is, I still have some
             | recollection from how I started to program and how alien it
             | all seemed. And note that I first started with 4 years of C
             | in high-school
             | 
             | However, I don't agree at all that having strings and
             | numbers as different things was ever a problem. On the
             | contrary, explaining that the same data can be interpreted
             | as both 40 and "0" is mistifying and very hard to grok, in
             | my experience. And don't get me started on how hard it is
             | to conceptualize pointers. Or working with the (implicit)
             | stack in assembly instead of being able to use named
             | variables.
        
           | mousethatroared wrote:
           | "is that it is extremely tedious, error prone, and sensitive
           | to details. It is also unstructured,"
           | 
           | That's why it's such an important first language!
           | Pedagogically it's the foundation motivating all the fancy
           | things languages give you.
           | 
           | You don't teach a kid to cut wood with a table saw. You give
           | them a hand saw!
        
             | ziml77 wrote:
             | You give them a hand saw because power tools are far easier
             | to inflict serious injuries with. But if you're teaching a
             | kid who's old enough, there's no reason to start on a hand
             | saw if you have the power tools available.
        
               | mousethatroared wrote:
               | You don't give a noob a table saw because he'll never
               | understand why a hand saw is useful. He'll never
               | appreciate that more often than not, the hand saw will
               | easier and quicker.
               | 
               | But hey, what do I know. Im the kind of guy who gets to
               | play with TMA and seriously considers purchasing
               | hydrazine for work. What do I know?
        
             | tsimionescu wrote:
             | No, it is not the foundation motivating what other
             | languages give you, not at all.
             | 
             | Programming languages are usually designed based on formal
             | semantics. They include constructs that have been found
             | either through experience or certain formal reasons to be
             | good ways to structure programs.
             | 
             | Haskell's lazy evaluation model, for example, has no
             | relationship to assembly code. It was not in any way
             | designed with thought to how assembly code works, it was
             | designed to have certain desirable theoretical properties
             | like referential transparency.
             | 
             | It's also important to realize that there is no "assembly
             | language". Each processor family has its own specific
             | assembly code with its own particular semantics that may
             | vary wildly from any other processor. Not to mention, there
             | are abstract assembly codes like WebAssembly or JVM
             | bytecode, which often have even more alien semantics.
        
               | mousethatroared wrote:
               | You don't teach lambda calculus to a first grader.
               | 
               | You don't teach Haskell to seventh grader.
               | 
               | But 4 bit assembly driving a few LEDs? That works
        
             | taco_emoji wrote:
             | > You don't teach a kid to cut wood with a table saw. You
             | give them a hand saw!
             | 
             | Okay but that's not for pedagogical reasons, it's because
             | power saws are MUCH more dangerous than hand saw.
             | 
             | Contrariwise, you don't teach a kid to drill wood with a
             | brace & bit, because a power drill is easier to use.
        
           | mystified5016 wrote:
           | Controversial opinion but we should be teaching new
           | programmers how a CPU works and not hand-wave the physical
           | machine away to the cloud.
           | 
           | Not doing this is how you get Electron.
        
         | UltraSane wrote:
         | x86 ASM absolutely is NOT a good first language due to it being
         | a complete mess.
        
           | rep_lodsb wrote:
           | 16 bit x86 isn't that complicated and (IMO) still helpful in
           | learning some of the more modern stuff. But I'd recommend
           | starting with either 6502, or the 8080, which is like the 8
           | bit "grandparent" of x86.
           | 
           | Avoid:
           | 
           | - Z80: at least as a first language. Extended 8080 with
           | completely different syntax, even more messy and unorthogonal
           | than x86!                   LD A,(HL)    ;load A from address
           | in HL register pair         LD A,(DE)    ;load A from address
           | in DE         LD B,(HL)    ;load B from address in HL
           | LD B,(DE)    ;invalid!              JP (HL)      ;load
           | program counter with contents of HL (*not* memory)
           | ADD A,B      ;add B to A         ADC A,B      ;add B to A
           | with carry         SBC A,B      ;subtract B from A with
           | borrow         SUB B        ;subtract B from A         OR B
           | ;logical-or B into A         etc.
           | 
           | - RISC-V: an architecture designed by C programmers, pretty
           | much exclusively as a target for compiling C to & omitting
           | anything not necessary for that goal
        
         | XorNot wrote:
         | This almost feels like an argument that we should teach
         | computer science via bare metal bootstrapping.
         | 
         | Start out at "here's your machine code. Let's understand how
         | x86_64 gets started" and work your way up to "now you have the
         | automation to compile Linux and a modern compiler".
         | 
         | Which would certainly have stops most of the way up for things
         | we usually include.
        
           | bitwize wrote:
           | So... NAND to Tetris?
        
         | aaronbaugher wrote:
         | I started with Z-80 assembly, then BASIC, then 6502 assembly,
         | then higher-level languages like C and perl, and I think the
         | assembly gave me a useful foundation for what was going on
         | under the hood. I'm not sure I'd even call assembly a
         | "language" in the sense of the others. It has instructions, not
         | statements, and there's really no syntax.
         | 
         | If I were teaching a general-interest programming course, I'd
         | probably start with just a bit of BASIC to introduce a few
         | broad concepts like variables and looping, then a little
         | assembly to say, "And this is what's going on when you do those
         | things," and then move up the chain. Then when they get to
         | something like C and go to look at the assembly it produces for
         | debugging, they'll at least be familiar with concepts like
         | registers and branching. So not quite the order I happened to
         | do it in, but similar.
        
         | vbezhenar wrote:
         | Beginners should have immediate positive feedback. It's not
         | possible with assembly language.
        
           | cbm-vic-20 wrote:
           | You can with a decent monitor that shows the values of
           | registers, can look up values in memory, etc.
        
           | myrmidon wrote:
           | Shenzhen I/O begs to disagree :P
           | 
           | https://www.zachtronics.com/shenzhen-io/
        
           | t-3 wrote:
           | It's just as straightforward as in higher level languages,
           | just not quite as interactive as interpreted languages, but
           | I've never seen an "intro to programming" that started in a
           | REPL even when using an interpreted language. Hello world is
           | even shorter and simpler than most languages (in a modern OS
           | environment).
        
             | rep_lodsb wrote:
             | The old D86 debugger[1][2] comes close to being a REPL for
             | assembly language, helped me a lot with learning it when I
             | found it on a shareware collection CD as a kid.
             | 
             | Load registers, call DOS or BIOS with 'int', etc. all
             | interactively and with a nice full screen display of
             | registers, flags and memory. Of course entering single
             | instructions to run immediately only gets you so far, but
             | you can also enter short programs into memory and single
             | step through them.
             | 
             | It's too bad nothing like this seems to exist for modern
             | systems! With the CPU virtualization features now
             | available, you could even experiment with ring 0 code
             | without fear of crashing your machine.
             | 
             | [1] http://eji.com/a86
             | 
             | [2] to run it under DOSBox, you may need to add the '+b4'
             | command line switch in order to bypass some machine
             | detection code
        
           | skydhash wrote:
           | You start with a simulator like this one:
           | 
           | https://edsim51.com/about-the-simulator/
           | 
           | Very immediate and positive feedback.
        
         | lo_zamoyski wrote:
         | > I have tried to convince people that ASM is reasonable as a
         | first stage teaching language.
         | 
         | Unless you're teaching people preparing for engineering
         | hardware perhaps, I think ASM is absolutely the wrong language
         | for this. The first reason is that programming is about problem
         | solving, not fiddling with the details of some particular
         | architecture, and ASM is pretty bad at clearly expressing
         | solutions in the language of the problem domain. Instead of
         | programming in the language of the domain, you're busy flipping
         | bits which are an implementation detail. It is really a
         | language for interfacing with and configuring hardware.
         | 
         | The more insidious result is that teaching ASM will make an
         | idol out of hardware by reinforcing the notion that computer
         | science or programming are about computing devices. It is not.
         | The computing device is totally auxiliary wrt subject matter.
         | It is utterly indispensable practically, yes, but it is not
         | what programming is concerned with per se. It is good for an
         | astronomer to be able to operate his telescope well, but he
         | isn't studying telescopes. Telescope engineers do that.
        
           | cvoss wrote:
           | Ooh, very much disagree with a lot of these assertions. The
           | problem I always encounter when trying to teach programming
           | is that students completely lack an understanding of how to
           | imagine and model the state of the computational system in
           | their heads. This leads to writing code that looks kinda like
           | it should do what the student wants, but betrays the fact
           | that they really don't understand what the code actually
           | means.
           | 
           | In order to successfully program a solution to a problem, it
           | is necessary to understand the system you are working with. A
           | machine-level programming language cuts through the
           | squishiness of that and presents a discrete and concrete
           | system whose state can be fully explained and understood
           | without difficulty. The part where it's all implementation
           | details is the benefit here.
        
             | lo_zamoyski wrote:
             | I suspect your background is dominated by imperative
             | languages, because these often bleed low-level, machine
             | concepts into the domain of discourse, causing a conceptual
             | muddle.
             | 
             | From a functional perspective, you see things properly as a
             | matter of language. When you describe to someone some
             | solution in English, do you worry about a "computational
             | system"? When writing proofs or solving mathematical
             | problems using some formal notation, are you thinking of
             | registers? Of course not. You are using the language of the
             | domain with its own rules.
             | 
             | Computer science is firmly rooted in the formal language
             | tradition, but for historical reasons, the machine has
             | assumed a central role it does not rightly possess. The
             | reason students are confused is because they're still
             | beholden to the machine _going into the course_ , causing a
             | compulsion to refer to the machine to know "what's really
             | going on" at the machine level. Instead of thinking of the
             | problem, they are worrying about distracting nonsense.
             | 
             | The reason why your students might _feel_ comforted after
             | you explain the machine model is because they already
             | tacitly expect the machine to play a _conceptual_ role in
             | what they 're doing. They stare and think "Okay, but what
             | does this have to do with computers?". The problem is
             | caused by the prior idolization of the machine in the first
             | place.
             | 
             | But machine code and a machine model are not the "really
             | real", with so-called "high-level languages" hovering above
             | them like some illusory phantom that's just a bit of
             | theater put on by 1s and 0s. The language exists in our
             | heads; machines are just instruments for simulating them.
             | And assembly language itself is just another language. It's
             | domain just is, loosely, the machine architecture.
             | 
             | So my view is that introductory classes should beat the
             | machine out of students' heads. There is no computer, no
             | machine. The first few classes in programming should omit
             | the computer and begin with paper and pencil and a small
             | toy language (a pure, lispy language tends to be very good
             | here). They should gain facility in this small language
             | first. The aim should be to make it clear that the language
             | is about talking about the domain, and that it stands on
             | its own, as it were; the computer is to programming as the
             | calculator is to mathematical calculation. Only once this
             | have been achieved are computers permitted, because large
             | programs are impractical to deal with using pen and paper.
             | 
             | This intuition is the foundation difference between a bona
             | fide compute science curriculum and dilettante tinkering.
        
               | rep_lodsb wrote:
               | Not everything that isn't "bona fide computer science"
               | should be considered "dilettante tinkering". In the real
               | world, code is run on physically existing machines, and
               | not in some abstract mathematical universe of pure
               | functions and infinite-length tapes.
        
               | lo_zamoyski wrote:
               | My remark was contextual. I am not saying there is no
               | value in in practical implementation. Obviously, there is
               | enormous value! But these are secondary to what computer
               | science is about, so if your concept of computer science
               | and programming are machine-centric, then this is by
               | definition not a computer science POV. If you take the
               | machine to be the primary object of computer science,
               | then you are either taking a computer engineering
               | position, or you gravely misunderstand the essence of
               | programming.
        
               | bigstrat2003 wrote:
               | I think that this is completely backwards. As James
               | Mickens put it: pointers are real; you can't just put a
               | LISP book on top of an x86 chip and hope it learns the
               | lambda calculus by osmosis. Computer science is, to be
               | honest, not interesting or useful without a machine to
               | use it on. Therefore trying to teach it to people without
               | reference to a machine is a grave error.
        
               | lo_zamoyski wrote:
               | > pointers are real
               | 
               | Pointers are an abstraction that are no more or less real
               | than any other abstraction. They belong to particular
               | languages, but they are not intrinsic to computer science
               | as such as if they were some kind of atomic construct of
               | the field.
               | 
               | > you can't just put a LISP book on top of an x86 chip
               | [...the rest is confusing...]
               | 
               | I'm not talking about what, _in today 's contingent
               | market and incidental state of the art_, is practical.
               | Obviously, if you want to run any program in any
               | language, you have to target _some_ architecture. The
               | point is that the architecture is utterly incidental as
               | far as the language per se is concerned. Lisp is not
               | "less real" because you need to translate it into machine
               | code. The machine code of a particular architecture is
               | only there to simulate Lisp on that architecture. You can
               | in principle have different architectures with their own
               | machine code that can be used to simulate the very same
               | Lisp.
               | 
               | > Computer science is, to be honest, not interesting or
               | useful without a machine to use it on.
               | 
               | Computer science is very interesting without a machine,
               | but how interesting you find it is neither here nor
               | there. The point isn't to do away with machines, or that
               | the machine has no practical importance. The point is to
               | say that the machine is only a tool, and not the subject
               | matter of computer science.
        
               | kazinator wrote:
               | Or, well, pointers are intrinsic to computer science, but
               | not in any special way. No more than the un-numbered
               | current position of the Turing tape machine along the
               | tape, or whatever.
               | 
               | We give a lot of attention to pointers because electronic
               | computers feature random access memory consisting of
               | small, equal-sized cells of bits, keyed by binary
               | numbers.
        
           | zahlman wrote:
           | > The first reason is that programming is about problem
           | solving, not fiddling with the details of some particular
           | architecture, and ASM is pretty bad at clearly expressing
           | solutions in the language of the problem domain. Instead of
           | programming in the language of the domain, you're busy
           | flipping bits which are an implementation detail.
           | 
           | "How do I use bits to represent concepts in the problem
           | domain?" is the fundamental, original problem of computer
           | science.
           | 
           | And to teach this, you use much simpler problems.
           | 
           | > ... reinforcing the notion that computer science or
           | programming are about computing devices. It is not.
           | 
           | It _is_ , however, about concepts like binary place-value
           | arithmetic, and using numbers (addresses) as a means of
           | indirection, and about using indirection to structure data,
           | and about being able to represent the instructions themselves
           | as data (such that they can be stored _somewhere_ with the
           | same techniques, even if we don 't assume a Von Neumann
           | machine), and (putting those two ideas together) about using
           | a number as a way to track a position in the program, and
           | manipulating that number to alter the flow of the program.
           | 
           | In second year university I learned computer organization
           | more or less in parallel with assembly. And eventually we got
           | to the point of seeing - at least in principle - how a basic
           | CPU could be designed, with its basic components - an ALU,
           | instruction decoder, bus etc.
           | 
           | Similarly:
           | 
           | > It is good for an astronomer to be able to operate his
           | telescope well, but he isn't studying telescopes.
           | 
           | The astronomer _is_ , however, studying _light_. And should
           | therefore have a basic mental model of what a lens is, how
           | lenses relate to light, how they work, and why telescopes
           | need them.
        
             | lo_zamoyski wrote:
             | > "How do I use bits to represent concepts in the problem
             | domain?" is the fundamental, original problem of computer
             | science.
             | 
             | > It is, however, about concepts like binary place-value
             | arithmetic
             | 
             | That is the original problem of using a particular digital
             | machine architecture. One shouldn't confuse the
             | practical/instrumental problems at the time with the field
             | proper. There's nothing special about bits _per se_. They
             | 're an implementation detail. We might study them for
             | practical reasons, we may study the limits of what can be
             | represented by or computed using binary encodings, or
             | efficient ways to do so or whatever, but that's not the
             | _central_ concern of computer science.
             | 
             | > In second year university I learned computer organization
             | more or less in parallel with assembly.
             | 
             | Sure. But just because a CS major learns these things
             | doesn't make it computer science per se. It's interesting
             | to learn, sure, and has practical utility, but particular
             | computer architectures are not the domain of computer
             | science. They're the domain of computer engineering.
             | 
             | > The astronomer is, however, studying light.
             | 
             | No, physicists studying optics study light in this
             | capacity. Astronomers _know_ about light, because knowledge
             | of light is useful for things like computing interstellar
             | distances or determining the composition of stellar objects
             | or for calculating the rate of expansion or whatever. The
             | same goes for knowledge of lenses and telescopes: they
             | learn _about_ them so they can _use_ them, but they don 't
             | _study_ them.
        
         | cameldrv wrote:
         | Personally way back when, I first learned BASIC, then tried to
         | learn C, but didn't get pointers, then learned ASM, and then
         | pointers became obvious, and went back to C. If you're going to
         | be using C or doing anything with hardware, learning ASM IMO is
         | very useful just to understand how the machine really works.
        
         | zahlman wrote:
         | > Getting them to do things is not hard, the difficulty comes
         | from tasks exceeding a scale where you can think about things
         | at their most basic level.
         | 
         | Indeed - you don't actually need to work on difficult tasks to
         | get the intellectual benefit. Once you've properly understood
         | what a computer is, you can absorb the ideas of SICP.
        
         | shortrounddev2 wrote:
         | assembly is a good first language if you have a simple
         | instruction set or machine. When I saw new people learn java,
         | easily the hardest initial bump to get over was "what the hell
         | is public static void main(String[] args) ?" or "eclipse didn't
         | build it for some reason"
         | 
         | Python is much easier to introduce someone to because there's
         | no boilerplate and the tooling is very simple. Assembly on x86
         | machines is a royal PITA to set up, and you also need some kind
         | of debugger to actively inspect the program counter and
         | registers.
         | 
         | When I took Computer Organization & Architecture, they had us
         | play around with MARIE[1] which really made assembly make sense
         | to me. After that, I wrote an 8080 emulator and it made even
         | MORE sense to me.
         | 
         | ---
         | 
         | [1] https://marie.js.org/
        
         | ferguess_k wrote:
         | I think in most CS programs, students do learn assembly early
         | on, perhaps not as the first language, but definitely as a
         | second language, as required by most Arch courses.
        
         | jcranmer wrote:
         | I was a TA for an intro to assembly language course, which
         | means I got my office hours full of all of the students who
         | struggled with assembly language and had to work with them one-
         | on-one to get them over their roadblocks to pass the class.
         | 
         | Assembly language is not a reasonable first programming
         | language. There's just so many things about it that make it a
         | poor choice for programming instruction.
         | 
         | Chiefly, assembly lacks structure. There's no such thing as
         | variables. There's no such thing as functions. You can fake
         | some of this stuff with convention, but if you make mistakes--
         | and students in intro-to-programming _will make mistakes_
         | --there is nothing that's going to poke you that you did
         | something wrong, you just get the wrong result.
        
       | flohofwoe wrote:
       | Here's a similar (and much more indepth) opcode decoding recipe
       | for Z80, very useful for emulator development:
       | 
       | http://www.z80.info/decoding.htm
       | 
       | For actually programming in machine code this understanding of
       | the internal opcode structure isn't all that useful though,
       | usually - without an assembler at hand - you had a lookup table
       | with all possible assembly instructions on the left side, and the
       | corresponding machine code bytes on the right side.
       | 
       | Programming by typing machine code into a hex editor is possible,
       | but really only recommended as absolute fallback if there's no
       | assembler at hand - mainly because you had to keep track of all
       | global constant and subroutine entry addresses - e.g. the main
       | thing that an assembler does for you, and you had to leave gaps
       | at strategic locations so that it is possible to patch the code
       | without having to move things around.
        
       | GuB-42 wrote:
       | Well, machine code _is_ scary. But like with many scary things,
       | once you overcome your fears and get familiar with the thing, you
       | realize that it is not that bad.
        
       | jebarker wrote:
       | ASM programming is fun. Machine code (as in what ASM encodes to)
       | isn't scary, but it is extremely tedious to work with. I
       | recommend the first part of Casey Muratori's Performance Aware
       | Programming course if you want to feel that pain.
        
         | ferguess_k wrote:
         | I think you need to do it in production to retain the
         | knowledge. If you just do it as a hobby, then most people just
         | give up at certain point because there is no point to bang your
         | head on the wall for nothing. You need to have a real problem
         | to solve to go a long way.
        
       | elif wrote:
       | This is a tangent but yesterday I was just pondering the
       | abstraction layer from machine code to assembly lexers to
       | compilers to interpreted languages. Having been lucky enough to
       | be born at a time to witness these shifts, it's so easy to forget
       | what we used to think was normal.
       | 
       | The thought came to me when testing the new Jules agentic coding
       | platform. It occured to me that we are just in another
       | abstraction cycle, but like those before, it's so hard to see the
       | shift when everything is shifting.
       | 
       | My conclusion? There will be non-AI coders, but they will be as
       | rare as C programmers before we realize it.
        
       | neomech wrote:
       | In 1982, I programmed my ZX81 by converting assembly to hex by
       | hand because BASIC was just too slow. I'd write my assembly on
       | paper, convert it to hex using reference tables, then use a
       | simple BASIC FOR loop to POKE the values into memory we'd
       | reserved space for the machine code in a REM statement at a fixed
       | position in memory.
       | 
       | When all the values were POKEd in, I'd save to tape and execute
       | it with RAND USR 16514.
       | 
       | That memory address is permanently etched in my brain even now.
       | 
       | It wasn't good, bad or scary it was just what I had to do to make
       | the programs I wanted to make.
        
         | stevekemp wrote:
         | I did the same thing, on the 48k Spectrum, a year or two later.
         | I also remembered to add some NOPs between functions, to avoid
         | me having to recalculate all the relative jump instructions if
         | I made changes.
        
       | kibwen wrote:
       | _> But what if we want to represent a number larger than 12 bits?
       | Well, the add instruction doesn 't let us represent all such
       | numbers; but setting sh to 1 lets us shift our number by 12 bits.
       | So for example we can represent 172032172032 by leaving our 42
       | alone and setting sh to 1. This is a clever technique for
       | encoding larger numbers in a small space._
       | 
       | This is whacky. So presumably adding with a 24-bit constant whose
       | value isn't representable in this compressed 13-bit format would
       | then expand to two add instructions? Or would it store a constant
       | to a register and then use that? Or is there a different single
       | instruction that would get used?
       | 
       | (Also, typo, 42 << 12 is 172032).
        
         | Joker_vD wrote:
         | Yes, it would:                   add_large_const:
         | add     w8, w0, #43, lsl #12                 add     w0, w8,
         | #42                 ret
         | 
         | The same happens e.g. on RISC-V:
         | add_large_const:                 lui     a5,43
         | addi    a5,a5,42                 add     a0,a0,a5
         | ret
         | 
         | Because there are only 32 bits in an instruction, you can't fit
         | a whole 32-bit immediate into it. Contrast it with x86 which
         | uses variable-length instructions (up to 15 bytes per
         | instruction):                   add_large_const:
         | lea     eax, [rdi+176170]    # this instruction takes 6 bytes
         | ret
         | 
         | P.S. Some people seem to be really puzzled by LEA instructions.
         | It's intended use is to correspond to C's "dest =
         | &base[offset]" which semantically is just "dest = base +
         | offset", of course -- but it allows one to express base and/or
         | offset using available addressing modes.
        
       | tasty_freeze wrote:
       | For the past year or so, a couple teen boys from my neighborhood
       | come by on sunday afternoon for a couple hours of programming in
       | python. I started very simply and built up with text based tasks,
       | then showed them pygame.
       | 
       | I am thinking about showing them what is under the hood, that
       | python itself is just a program. When I learned to program it was
       | the late 70s, and trs-80s and apple-IIs were easy to understand
       | at the machine code level.
       | 
       | I could recapitulate that experience for them, via an emulator,
       | but that again just feels like an abstraction. I want them to
       | have the bare-metal experience. But x86 is such a sprawling,
       | complicated instruction set that it is very intimidating. Of
       | course I'd stick to a simplified subset of the instructions, but
       | even then, it seems like a lot more work to make output running
       | on a PC vs on the old 8-bit machines where you write to a
       | specific location and it shows up on the screen.
        
         | TuringTourist wrote:
         | You could try the thing that made it click for me, long after
         | x86 was dominant.
         | 
         | Show them a CPU running on Logisim (or the like, such as the
         | newer Digital) and show how when you plug a program into a ROM,
         | it turns into wires lighting up and flipping gates/activating
         | data lines/read registers etc.
        
         | ThrowawayR2 wrote:
         | Buy them a copy of "Human Resource Machine" on Steam or
         | (preferably since there's no DRM) Good Old Games. It's a
         | gamified version of what writing machine language on the old 8
         | bit CPUs of yore was like. The puzzle challenge in HRM is
         | authentic in the sense that it derives from the natural
         | constraints of having a single accumulator and very simple
         | instructions rather than unnaturally injected constraints like
         | the Zachtronics games, which are good but I wouldn't recommend
         | as a learning tool.
        
       | redf1sh wrote:
       | Ok, what about VLIW ASM? Have you ever seen Elbrus' ASM with
       | predicated code, asynchronous Array Prefetch Buffer, rotating
       | registers, DAM (hardware table to memory dependencies
       | disambiguation), registers windows etc. It's really hard to start
       | read this.
        
       | addaon wrote:
       | I think this article is missing a major point, or perhaps should
       | be titled "Some Non-Scary Machine Code Isn't Scary". It argues
       | that machine code isn't scary, by building a one-to-one mapping
       | from machine code to assembly code, and then taking it as given
       | that assembly code isn't scary. But it uses two examples --
       | 32-bit ARM and x86-64 -- where this one-to-one mapping isn't
       | valid. When in Thumb mode for (some flavors of) ARM, even when
       | you know you're in thumb mode, instructions can be a mix of 16
       | and 32 bits. And in x86 world, of course, instructions can be a
       | wide range of widths. What that means is that if you're given a
       | chunk of memory that is known to contain executable
       | instructions... you /can't/ build a one-to-one mapping to
       | assembly without knowing where all of the entry points are. For
       | well-formed code you can often exclude almost all possible entry
       | points as invalid, and maybe even end up with only a single
       | one... but it's perfectly possible (and quite fun) to write
       | machine code that has valid, different behavior for different
       | entry points to the same byte sequence. There's no way to reduce
       | this type of machine code to meaningful assembly, and it should
       | be considered scary.
        
       | HeyLaughingBoy wrote:
       | Reading this thread leaves me with the impression that most
       | posters advocating learning assembly language have never had to
       | use it in a production environment. It sucks!
       | 
       | For the overwhelming majority of programmers, assembly offers
       | absolutely no benefit. I learned (MC6809) assembly after learning
       | BASIC. I went on to become an embedded systems programmer in an
       | era where compilers were still pretty expensive, and I worked for
       | a cheapskate. I wrote an untold amount of assembly for various
       | microcontrollers over the first 10 years of my career. I honestly
       | can't say I got any more benefit out of than programming in C; it
       | just made everything take so much longer.
       | 
       | I once, for a side gig, had to write a 16-bit long-division
       | routine on a processor with only one 8-bit accumulator. That was
       | the point at which I declared that I'd never write another
       | assembly program. Luckily, by then gcc supported some smaller
       | processors so I could switch to using Atmel AVR series.
        
         | zahlman wrote:
         | > most posters advocating learning assembly language have never
         | had to use it in a production environment... For the
         | overwhelming majority of programmers, assembly offers
         | absolutely no benefit.
         | 
         | I don't follow. Why should assembly have to be useful or
         | pleasant in a production environment, for learning it to be
         | useful?
         | 
         | I was taught a couple different flavours of assembly in
         | university, and I found it quite useful for appreciating what
         | the machine actually does. Certainly more so than C.
         | Abstractions do ultimately have to be rooted in something.
        
           | atoav wrote:
           | You and the post you commented on display both a valid point.
           | If we're talking about using assembly as a broad general
           | purpose programming environment that would be a mess (which
           | is precisely why it has no broad adoption). When we talk
           | about assembly as a niche special purpose solution we would
           | come to a different conclusion, coincidentally this is where
           | assembly is still used today: environments where we need
           | highly optimized code.
           | 
           | Your point about education is orthogonal to the point made. I
           | agree with you that learning assembly can be a good way to
           | teach people how computers work on a low level, but that has
           | nothing to do with whether it is useful as a skill to learn.
           | 
           | As someone teaching similar things at the university level to
           | a non-tech audience I have to always carefully wheigh how
           | much "practically useless" lessons a typical art student can
           | stomach. And which kind of lesson will just deter them,
           | potentially forever.
        
             | zahlman wrote:
             | > I agree with you that learning assembly can be a good way
             | to teach people how computers work on a low level, but that
             | has nothing to do with whether it is useful as a skill to
             | learn.
             | 
             | I don't understand the distinction you're trying to make.
             | The post I was replying to specifically discussed "learning
             | assembly language". My entire point is that "learning
             | assembly language" has purposes other than creating
             | practical real-world programs in assembly.
        
           | bongodongobob wrote:
           | Is it useful to learn bagpipes? I guess learning for its own
           | sake is good, but if you want to join a band, guitar or
           | keyboards are going to be a better bet and learning bagpipes
           | first isn't going to do much for you.
        
             | barrkel wrote:
             | Do bagpipes explain the mystery of sand performing
             | calculations and taking actions? Do they give you an
             | intuition for connecting how CPUs and memory accesses and
             | cache hierarchies work with high level code, in such a way
             | that you can start to understand why one version of code
             | might be faster or slower than another?
             | 
             | If you can't see through field accesses and function calls
             | to memory indirections, anything you might read about how
             | TLBs and caches and branch prediction work doesn't connect
             | to much.
        
               | bongodongobob wrote:
               | Guess what, almost no one knows how to program in
               | assembly and yet everything is working out pretty good.
        
               | barrkel wrote:
               | I can say the performance of Windows Explorer lately,
               | compared to how it was in Windows NT, does not impress
               | me.
        
             | spc476 wrote:
             | Learning the accordion didn't hurt Weird Al's career, nor
             | did using the flute hurt Ian Anderson (lead vocalist and
             | flutist of Jethro Tull).
        
               | bongodongobob wrote:
               | These are edge cases. Way to miss the point.
        
             | strken wrote:
             | If a guitar was an abstraction layer that was implemented
             | by low-level bagpipes then a) that would be awesome and b)
             | guitar players would find their guitar playing to benefit
             | from bagpipe lessons. At the very least they'd be able to
             | understand and maintain their guitar better.
        
               | bongodongobob wrote:
               | The connection is that they both play notes. You can play
               | the same songs on both but no one wants to hear bagpipes.
        
               | SAI_Peregrinus wrote:
               | You _can 't_ play most of the same songs on both.
               | Bagpipes (well, most forms of bagpipe, there are dozens,
               | but unqualified people tend to mean the Scottish "Great
               | Highland Bagpipe") are a diatonic instrument playing a
               | just-intonation scale tuned to not cause discordant notes
               | with their own drones, while guitars are a chromatic
               | instrument fretted to play an equal-tempered intonation.
               | The GHB plays in something rather close to the modern
               | Mixolidian A mode with an augmented 4th, not any of the
               | major or minor keys of modern Western music. The GHB and
               | the guitar are entirely incompatible instruments, unless
               | you're talking about a classical guitar with tied-on gut
               | frets that could be replaced to allow playing the GHB
               | scale.
        
               | HeyLaughingBoy wrote:
               | I have no idea what any of that means, but I love the
               | deep knowledge that it expresses :-)
        
               | strken wrote:
               | What you're trying to say is that assembly is like the
               | bagpipes and impractical. What I'm trying to say is
               | that's a terrible metaphor because the main reason to
               | learn assembly is understanding what your non-assembly
               | code is actually executed as.
        
         | craftkiller wrote:
         | I never used it in production and yet learning it absolutely
         | provided me with benefits. I didn't understand pointers until I
         | spent a weekend learning assembly.
        
         | ajross wrote:
         | > Reading this thread leaves me with the impression that most
         | posters advocating learning assembly language have never had to
         | use it in a production environment. It sucks!
         | 
         | It absolutely sucks. But it's not _scary_. In my world (Zephyr
         | RTOS kernel) I routinely see people go through all kinds of
         | contortions to build abstractions around what are actually
         | pretty straightforward hardware interfaces. Like, here 's an
         | interrupt controller with four registers. And here's a C API in
         | the HAL with 28 functions and a bunch of function pointer
         | typedefs and handler mechanics you're supposed to use to talk
         | to it. Stuff like that.
         | 
         | It's really common to see giant abstractions built around
         | things that could literally be two-instruction inline assembly
         | blocks. And the reason is that everyone is scared of "__asm__".
        
           | K0balt wrote:
           | This exactly. If you are doing embedded programming, direct
           | register access and manipulation is often a far, far superior
           | option, and you don't have to be some kind of "assembly
           | sensei" to do it if you just have a very basic idea of how
           | things work. It doesn't mean you write programs in
           | assembly... it means when you are needing to do something
           | that the hardware is going to do for you anyway, you know how
           | to ask for it directly without having to load a 2Kloc
           | library. This is especially true when using python or JS
           | bytecode on the MCU. Actually, using python with assembly is
           | really the best of both worlds in many cases.
        
           | HeyLaughingBoy wrote:
           | Yeah, but doesn't the Zephyr device tree abstraction actually
           | expect you to do that? I mean, I appreciate the elegance and
           | the desire for portability, but all I could think of as I
           | read those docs was "here's a couple months of work for
           | something that should take ten minutes."
        
             | ajross wrote:
             | DTS[1] is there to parametrize things (like MMIO addresses
             | and IRQ assignments) that need to be parametrized. The
             | discussion here is about needless abstraction at the level
             | of C code.
             | 
             | In, say, the interrupt controller case: there's a lot of
             | value in having a generic way for boards to declare what
             | the IRQ for a device actually is. But the driver should be
             | stuffing that into the hardware or masking interrupt
             | priorities or whatever using appropriately constructed
             | assembly where needed, and not a needless layer of C code
             | that just wraps the asm blocks anyway.
             | 
             | [1] And to be clear I'm not that much of a devicetree
             | booster and have lots of complaints within the space, both
             | about the technology itself and the framework with which
             | it's applied. But none that would impact the point here.
        
         | a_cardboard_box wrote:
         | > I once, for a side gig, had to write a 16-bit long-division
         | routine on a processor with only one 8-bit accumulator. That
         | was the point at which I declared that I'd never write another
         | assembly program.
         | 
         | This is exactly the kind of job I'd enjoy! A perfectly doable
         | technical challenge with clear requirements. Some people like
         | solving Sudoku puzzles, I like solving programming puzzles.
         | 
         | I guess I'm just not "the overwhelming majority of
         | programmers".
        
           | markus_zhang wrote:
           | I totally agree. I read and commented the source code of
           | Woz's SWEET16 and it was a blast to fully understand it.
           | 
           | But of course, might not be that rosy if under great time
           | constraints.
        
           | HeyLaughingBoy wrote:
           | > doable technical challenge with clear requirements
           | 
           | That's a Project Management issue, not an implementation
           | concern.
           | 
           | In my case, there was no requirement that said "use 16-bit
           | long division." However, we had committed to a particular
           | processor family (MC68HC05), and the calculation precision
           | required 16-bit math. IIRC, there was a compiler available,
           | but it cost more than the rest of the project and the code it
           | produced wouldn't have fit into the variant of the processor
           | that I was using anyway.
           | 
           | The actual requirement would have looked more like "detect a
           | 0.1% decrease in signal that persists for 10 seconds, then do
           | X."
        
             | Animats wrote:
             | Oh, yes, that era. I had to program a MC68HC11 in Forth
             | because the C compiler was so expensive.
        
               | markus_zhang wrote:
               | Man what a blast!
        
           | commandlinefan wrote:
           | > the kind of job I'd enjoy
           | 
           | I feel the same way, but I also can't help but imagine the
           | boss jumping up and down and throwing chairs and screaming
           | "how can you not be done yet? You're a programmer and this is
           | a program and it's been three _hours_ already".
        
           | favorited wrote:
           | I think the majority of programmers would enjoy it, but most
           | would first need to pick an ISA (something older is probably
           | going to be more approachable for beginners), learn enough
           | about it to understand basic arithmetic instructions, learn
           | enough about the dev tools to be able to assemble, link, and
           | execute their code, etc.
           | 
           | For most folks, that's going to be a couple days of prep work
           | before they can get to the fun part of solving the puzzle.
        
           | 1vuio0pswjnm7 wrote:
           | "I guess I'm just not the "overwhelming majority of
           | programmers"."
           | 
           | The "overwhelming" majority of programmers may be
           | underwhelming
           | 
           | Some readers may be unimpressed by programmers who complain
           | about and criticise assembly language, e.g., claiming it
           | offers "no benefit" to others, especially when no one is
           | forcing these programmers to use it
        
         | wat10000 wrote:
         | I've written assembly in a production environment. I love it
         | and wish I could do more.
         | 
         | But the context where I'm doing it is very different from the
         | context where you had to write a division routine from scratch!
         | We never use assembly where a higher-level language would be
         | good enough. It's only used for things that can't be written in
         | C at all, either because it needs an instruction that the C
         | compiler won't emit, or it involves some special calling
         | convention that C can't express.
         | 
         | However, I _read_ assembly in production all the time.
         | Literally every day on the job. It 's absolutely essential for
         | crashes that won't reproduce locally, issues caused by compiler
         | bugs, or extremely sensitive performance work. Now, lots of
         | programmers very rarely have to deal with those sorts of
         | things, but when it comes up, they'll be asking for help from
         | the ones who know this stuff.
        
           | xxpor wrote:
           | +1 on reading.
           | 
           | I hardly consider myself an expert ARM ASM programmer (or
           | even an amateur...), but a baseline level of how to read it
           | even if you have to look up a bunch of instructions every
           | time can be super useful for performance work, especially if
           | you have the abstract computer engineering know how to back
           | it up.
           | 
           | For example, it turns out that gcc 7.3 (for arm64) doesn't
           | optimize                  foo() ? bar() : baz();
           | 
           | the same as                   if (foo()) {            bar();
           | } else {            baz();         }
           | 
           | !
           | 
           | The former was compiled into a branchless set of
           | instructions, while the latter had a branch!
        
           | ferguess_k wrote:
           | Just curious, what kind of work do you do? Sounds like SRE in
           | FAANG that deals with production systems. I work as a DE and
           | the lowest level thing I have to read is JVM dump from spark.
           | Man I envy you.
        
             | wat10000 wrote:
             | Close, OS development at a FAANG.
        
         | flohofwoe wrote:
         | On 8-bit home computer CPUs like the 6502 or Z80, high level
         | programming languages like C simply were not an option, you
         | left too much performance on the table (not to mention BASIC
         | which was easily 100x slower than handwritten assembly).
         | 
         | Forth _was_ quite acceptable performance wise, but that 's
         | barely above a good macro assembler.
         | 
         | And after the 8-bitters, assembly coding on the Amiga was pure
         | pleasure - also for large programs, since apart from the great
         | 68k ISA the entire Amiga hardware and operating system was
         | written to make assembly coding convenient (and even though C
         | was much better on the 68k, most serious programs used a mix of
         | C and assembly).
         | 
         | (also, while writing assembly code today isn't all that
         | important, reading assembly code definitely is when looking at
         | compiler output and trying to figure out why and how the
         | compiler butchered my high level code).
        
           | acegopher wrote:
           | > the entire Amiga hardware and operating system was written
           | to make assembly coding convenient
           | 
           | I am curious what specific examples do you have of the HW and
           | OS being made/written to make ASM convenient?
        
             | flohofwoe wrote:
             | The hardware could be controlled via memory mapped 16-bit
             | registers, e.g. checking whether the left mouse button is
             | down is a single instruction:                   btst #6,
             | $bfe001
             | 
             | The OS used a simple assembly-friendly calling convention,
             | parameters were passed in registers instead of the stack
             | (and the API documentation mentioned which parameters are
             | expected in which registers), and the reference manuals
             | usually had both C and assembly examples, etc... basically
             | lots of little things to make the lives of assembly coders
             | easier.
             | 
             | This YouTube playlist gives a nice overview of assembly
             | coding on the Amiga (mostly via direct hardware access
             | though): https://www.youtube.com/playlist?list=PLc3ltHgmiid
             | pK-s0eP5hT...
        
               | kragen wrote:
               | Also, using a 68000 instead of a shitty Intel processor
               | was a huge boon to assembly programming. Ultimately Intel
               | won in the market and eventually even shipped processors
               | that weren't profoundly unpleasant at the assembly level,
               | but the 68000 is still a much more pleasant architecture
               | for the assembly programmer. ARM is nicer still, but this
               | was before ARM's existence as a separate company from
               | Acorn.
        
           | pjmlp wrote:
           | To add to that, there is a reason why even all modern JITs
           | also have ways to look into generated code.
           | 
           | Anyone curious how their JVM, CLR, V8, ART, Julia,.... gets
           | massaged into machine code only needs to learn about the
           | related tools on the ecosystem.
           | 
           | Some of them are available on online playgrounds like
           | Compiler Explorer, Sharpio,....
        
           | jamesfinlayson wrote:
           | > (also, while writing assembly code today isn't all that
           | important, reading assembly code definitely is when looking
           | at compiler output and trying to figure out why and how the
           | compiler butchered my high level code).
           | 
           | Agreed - I wouldn't be able to write any x86 assembly without
           | a bit of help, but having done some game reverse engineering
           | I've learned enough to make sense of compiler generated code.
        
         | ferguess_k wrote:
         | Most of us do not have the chance to use it in production. I
         | think that's where the fancy came from.
         | 
         | We are also getting burned out by the modern Agile
         | web/data/whatever development scene and would like to drill
         | really deep into one specific area without stakeholders
         | breathing down our necks every few hours, which assembly
         | programming conveniently provides.
         | 
         | I also consider the grit (forced or voluntary) to be a bath of
         | fire which significantly improved two important things - the
         | programmer's understanding of the system, and the programmer's
         | capability to run low level code in his brain. Is it suffering?
         | Definitely, but this is a suffering that bring technical
         | prowess.
         | 
         | Most of us do not have the privilege to suffer properly. Do you
         | prefer to suffer from incomplete documentation, very low level
         | code and banging your head on a wall for tough technical
         | problems, or do you prefer to suffer from incomplete
         | documentation, layers and layers of abstraction, stakeholders
         | changing requirements every day and actually know very little
         | about technical stuffs? I think it is an easy choice, at least
         | for me. If there is an assembly language / C job that is
         | willing to take me in, I'll do it in half of the salary I'm
         | earning.
        
         | WalterBright wrote:
         | I did a lot of assembler programming before discovering C. I
         | learned C in maybe an hour because of that.
         | 
         | Not knowing assembler means programmers have a bit of a blind
         | spot towards what are expensive things to do in C vs what
         | generates the best code.
         | 
         | For example, debugging a program sometimes requires looking at
         | the generated assembler. Recently I was wondering why my
         | deliberate null pointer dereference wasn't generating an
         | exception. Looking at the assembler, there were no instructions
         | generated for it. It turns out that since a null pointer
         | dereference was undefined behavior, the compiler didn't need to
         | generate any instructions for it.
        
           | ozim wrote:
           | I build web applications that run on top of databases, web
           | servers and frameworks.
           | 
           | I do need to understand how indexes in db engine work, I need
           | to understand there might be socket exhaustion in the system,
           | I do need to understand how my framework allocates data on
           | heap vs stack.
           | 
           | Having to drop to instructions that is for web servers, db,
           | frameworks developers not for me to do. I do have a clue how
           | low level works but there is no need for me.
           | 
           | That is part where parent poster is correct there are better
           | ways for developers to spend time on - trust your database,
           | web servers and framework and learn how those work in depth
           | you can skip asembler, because all of those will take a lot
           | of time anyway and most likely those are the ones you
           | should/can tweak to fix performance not assembler.
        
           | cogman10 wrote:
           | The issue is it's a moving target. What was expensive
           | yesterday could be fast today based on compiler optimizations
           | (and potentially vice versa).
           | 
           | Further, changes in the ISA can open up gains in performance
           | that weren't available in yesteryear. An example of this
           | would be SIMD instruction usage.
           | 
           | It's not a bad idea to know enough assembly language to
           | understand why code is slow. However, the general default
           | should be to avoid writing it. Your time would be better
           | spent getting a newer version of your compiler and
           | potentially enabling things like PGO.
        
           | marssaxman wrote:
           | > since a null pointer dereference was undefined behavior,
           | the compiler didn't need to generate any instructions for it.
           | 
           | I deeply hate this attitude in modern compiler design.
        
             | WalterBright wrote:
             | Me too. My compilers don't do that.
        
               | marssaxman wrote:
               | I'm glad to hear it. Thank you for caring.
        
         | Const-me wrote:
         | I think writing assembly indeed offers no benefit for most
         | developers. However, being able to read and understand assembly
         | is generally useful.
         | 
         | Enables debugging binaries and crash dumps without complete
         | source codes, like DLLs shipped with Windows or third-party
         | DLLs. Allows to understand what compilers (both traditional and
         | JIT) did to your source codes, this is useful when doing
         | performance optimizations.
        
           | anta40 wrote:
           | I write mobile apps for living (mostly Java/Kotlin, a little
           | bit of Flutter/RN) so yeah agree assembly is practically
           | useless for professional work.
           | 
           | But for tinkering (e.g writing GBA/NES games), hell why not?
           | It's fun.
        
         | kragen wrote:
         | Programming in assembly is _slow_. It takes a long time to make
         | things that way; as Julia Ecklar sings, it 's kind of like
         | construction work with a toothpick for a tool.
         | (https://www.youtube.com/watch?v=WZCs4Eyalxc) But that's also
         | true of knitting
         | (https://journal.stuffwithstuff.com/2025/05/30/consider-
         | knitt...), crochet, plasterwork, childrearing, calligraphy,
         | gardening, carving marble, hand-soldering electronics, watching
         | sunrises, and solving crossword puzzles.
         | 
         | If you have a six-day deadline, probably it would be better to
         | use a high-level language instead.
         | 
         | But, when you have time for them, all of these things are
         | intrinsically rewarding. Not all the time! And not for
         | everyone! But for some of us, some of the time, they can all be
         | very enjoyable. And sometimes that slow effort can achieve a
         | result that you can't get any other way.
         | 
         | I haven't written that much assembly, myself. Much less than
         | you have. If I had to write everything in assembly for years,
         | maybe I wouldn't enjoy it anymore. I've written a web server, a
         | Tetris game, some bytecode interpreters, a threading library, a
         | 64-byte VGA graphics demo, a sort of skeletal music
         | synthesizer, and an interpreter for an object-oriented language
         | with pattern-matching and multiple dispatch, as well as a
         | couple of compilers in high-level languages targeting assembly
         | or machine code. All of these were either 8086, ARM, RISC-V,
         | i386, or amd64; I never had to suffer through 6809 or various
         | microcontrollers.
         | 
         | Maybe most important, I've never written assembly code that
         | someone else depended on working. Those programs I've mostly
         | written in Python, which I regret now. It's much faster that
         | way. However, I've found it useful in practice for debugging C
         | and C++ programs.
         | 
         | I think that a farmer who says, "For the vast majority of
         | consumers, gardening offers absolutely no benefit," is missing
         | the point. It's not about easier access to parsley and chives.
         | Similarly for an author who says, "For the vast majority of
         | readers, solving crossword puzzles offers absolutely no
         | benefit."
         | 
         | So I don't think assembly _sucks_.
        
           | chubot wrote:
           | That's kind of how I feel about C. C is fun, because you get
           | to see "everything"
           | 
           | But C is slow to create -- it is like using a toothpick
           | 
           | Writing from scratch is slow, and using C libraries also
           | sucks. Certainly libc sucks, e.g. returning pointers to
           | static buffers, global vars for Unicode, etc.
           | 
           | So yeah I have never written Assembly that anybody needs to
           | work, but I think of it as "next level slow"
           | 
           | ---
           | 
           | Probably the main case where C is nice is where you are
           | working for a company that has developed high quality
           | infrastructure over decades. And I doubt there is any such
           | company in existence for Assembly
        
             | kragen wrote:
             | Yeah, from the point of view of Python or the Bourne shell,
             | assembly is _C_ 2. Like _E_ / _m_.
        
               | za3k wrote:
               | Good joke. _E /m_ looks almost exactly like the
               | programming language _Elm_ though so took me a bit.
        
           | alcover wrote:
           | > as Julia Ecklar sings, it's kind of like construction work
           | with a toothpick for a tool.                   I was taught
           | assembler         in my second year of school.         It's
           | kinda like construction work --         with a toothpick for
           | a tool.         So when I made my senior year,         I
           | threw my code away,         And learned the way to program
           | that I still prefer today.                  Now, some folks
           | on the Internet         put their faith in C++.         They
           | swear that it's so powerful,         it's what God used for
           | us.         And maybe it lets mortals dredge         their
           | objects from the C.         But I think that explains
           | why only God can make a tree.                  For God wrote
           | in Lisp code         When he filled the leaves with green.
           | The fractal flowers and recursive roots:         The most
           | lovely hack I've seen.         And when I ponder snowflakes,
           | never finding two the same,         I know God likes a
           | language         with its own four-letter name.
           | Now, I've used a SUN under Unix,         so I've seen what C
           | can hold.         I've surfed for Perls, found what Fortran's
           | for,         Got that Java stuff down cold.         Though
           | the chance that I'd write COBOL code         is a SNOBOL's
           | chance in Hell.         And I basically hate hieroglyphs,
           | so I won't use APL.                  Now, God must know all
           | these languages,         and a few I haven't named.
           | But the Lord made sure, when each sparrow falls,         that
           | its flesh will be reclaimed.         And the Lord could not
           | count grains of sand         with a 32-bit word.         Who
           | knows where we would go to         if Lisp weren't what he
           | preferred?                  And God wrote in Lisp code
           | Every creature great and small.         Don't search the disk
           | drive for man.c,         When the listing's on the wall.
           | And when I watch the lightning burn         Unbelievers to a
           | crisp,         I know God had six days to work,         So he
           | wrote it all in Lisp.                  Yes, God had a
           | deadline.         So he wrote it all in Lisp.
        
             | drob518 wrote:
             | True. I love assembly language, but I write my code in
             | Clojure.
        
         | WalterBright wrote:
         | Sometimes you don't really want to write in assembler. Like
         | loading a constant into a register for the AArch64. The
         | instructions to do it are pretty wacky, and it's hard to see if
         | you wrote the correct combination to load the value. Best to
         | let the compiler do it for you (or use godbolt.org! to get the
         | right mix). The same for floating point constants.
         | 
         | Once I got the code sequences for this right on my AArch64 code
         | generator, I don't have to ever figure it out again!
        
           | vardump wrote:
           | I expect a sufficiently good macro assembler should be able
           | to do it as well.
        
             | WalterBright wrote:
             | Then you might as well use a HLL.
        
           | fuhsnn wrote:
           | This post was very helpful when I tried to figure it out:
           | https://dougallj.wordpress.com/2021/10/30/bit-twiddling-
           | opti...
        
             | WalterBright wrote:
             | I could have used that during the hours I spent figuring it
             | out!
        
         | commandlinefan wrote:
         | yeah, it's not _scary_. It's just tedious.
        
         | pjmlp wrote:
         | As someone that has spent some time in the 8 and 16 bit
         | demoscene, I used my share of Z80, 80x86 and 68000.
         | 
         | It is all a matter of having high quality macro assemblers, and
         | people that actually care to write structured documented code
         | in Assembly.
         | 
         | When they don't care, usually not even writing in C and C++
         | will save the kind of code they write.
        
         | mystified5016 wrote:
         | If you have a less-popular CPU, compilers today can be utter
         | _trash_. GCC doesn 't understand the TinyAVR core and emits
         | insane assembly. Like iterating an array, instead of putting
         | the array pointer in the Z register and using the atomic load-
         | and-increment instructions, it will add to the pointer, read,
         | subtract from the pointer, loop. It also uses the slower load
         | instruction. Overall, looping over an array in C is 4 times
         | slower than assembly, and consumes three times as much program
         | space. Try examining the assembly from your next program,
         | you'll probably be quite surprised at how awful it is.
         | 
         | I had to implement Morton ordering on this platform. The
         | canonical C for this blows up to over 300 instructions per
         | iteration. I unrolled the loop, used special CPU hardware and
         | got the entire thing in under 100 instructions.
         | 
         | Compilers, even modern ones, are not magic and only understand
         | CPUs popular enough to receive specific attention from compiler
         | devs. If your CPU is unpopular, you're doing optimizations
         | yourself.
         | 
         | Assembly doesn't matter to arduino script kiddies, but it's
         | still quite important if you care at all about execution speed,
         | binary size, resource usage.
        
         | grishka wrote:
         | I've also heard the opinion that modern compilers are better at
         | generating optimized code than someone writing assembly by
         | hand. Not sure how true it is, but considering the unfathomable
         | complexity of modern CPUs, it does feel believable.
        
           | mabster wrote:
           | As a low level performance guy I trust the compiler nowadays,
           | especially with deep instruction pipelines. The compiler is
           | beatable - a lot of the decisions are heuristic - but it
           | takes a lot of work to beat it.
        
           | GianFabien wrote:
           | Last time I looked intel CPUs had like 1700 instructions.
           | Every generation comes with an even more expanded ISA. I
           | doubt that compilers use even a fraction of the ISA.
           | Especially considering that binaries are often expected to
           | run on a wide range of older CPUs. I know that there are
           | intrinsic functions which provide access to some of the
           | powerful, yet special purpose instructions. It is unrealistic
           | to expect the compiler to make effective use of all the fancy
           | instructions you paid for with your latest hardware upgrade.
        
             | genewitch wrote:
             | > It is unrealistic to expect the compiler to make
             | effective use of all the fancy instructions you paid for
             | with your latest hardware upgrade.
             | 
             | I'd add "yet" - we runinafed that the reason new machines
             | with similar shapes (quad core to quad core of a newer
             | generation) doesn't immediately seem like a large a jump as
             | it ought, in performance, is because it takes time for
             | people other than intel to update their compilers to
             | effectively make use of the new instructions. icc is
             | obviously going to more quickly (in the sense of how long
             | after the CPU is released, not `time`) generate faster
             | executing code on new Intel hardware. But gcc will take
             | longer to catch up.
             | 
             | There's a sweet spot from about 1-4 years after initial
             | release where hardware speeds up, but toward the end of
             | that run programs bloat and wipe all the benefits of the
             | new instructions; leading to needing a new CPU, that isn't
             | that much faster than the one you replaced.
             | 
             | Yet.
             | 
             | Which reminds me I need to benchmark a Linux kernel compile
             | to see if my above supposition is correct, I have the
             | timings from when I first bought it, as compared to a 10
             | year old HP 40 core machine (ryzen 5950 is 5% faster but
             | used 1/4th the wall power.)
        
             | grishka wrote:
             | These kinds of SIMD instructions are usually used by things
             | like media codecs and DSPs. They would include several
             | versions of the performance-critical number-crunching code
             | and would pick the best one at runtime depending on which
             | SIMD instructions your CPU supports.
        
           | mystified5016 wrote:
           | If and only if someone has taken time to write specific
           | optimizations for your specific CPU.
           | 
           | In embedded land, if your microcontroller is unpopular, you
           | don't get much in the way of optimization. The assembly GCC
           | generates is frankly hot steaming trash and an intern with an
           | hour of assembly experience can do better. This is not in any
           | way an exaggeration.
           | 
           | I've run into several situations where hand-optimized
           | assembly is _tens_ of times faster than optimized C mangled
           | by GCC.
           | 
           | I do not trust compilers anymore unless it's specifically for
           | x86_64, and only for CPUs made this decade
        
         | m463 wrote:
         | I've used "machine code" plenty of times in production as
         | inline assembly encoded in other languages.
         | 
         | I vaguely recall ada inline assembly looking like function
         | calls, with arguments that sometimes referenced high-level-
         | language variables)
         | 
         | unrelated to that, I distinguish between machine code which is
         | binary/hex, and assembly as symbolic assembler or macro
         | assembler, which can actually have high level macros and other
         | niceties.
         | 
         | And one thing I can say for sure. I took assembly language as
         | my second computer course, and it definitely added a lifelong
         | context as to how machines worked, what everything translated
         | to and whether it was fast or efficient.
        
           | HeyLaughingBoy wrote:
           | LOL. As a poor college student, I couldn't even afford an
           | assembler. Programming my CoCo (Radio Shack Color Computer)
           | had to be done either with the built-in BASIC, or by POKEing
           | in machine codes for programs that I hand assembled. One of
           | the nice things about Motorola (CoCo was based on MC6809E)
           | assembly languages is that the processors were very regular
           | and it was easy to remember the opcodes and operation
           | structures.
           | 
           | A friend of mine who also had a CoCo wrote an assembler as a
           | term project.
        
         | mabster wrote:
         | I started my career in assembly and it's reduced over time.
         | Towards the end of the gamedev work I was still reading a lot
         | of assembly but no longer writing it (using intrinsics
         | instead). It was definitely a lot slower to write.
         | 
         | But there are a number of things we did that are not available
         | or difficult in C:
         | 
         | - Guaranteed tail calls
         | 
         | - Returning multiple values without touching memory
         | 
         | - using the stack pointer as a general purpose pointer for
         | writing to memory
         | 
         | - Changing the stack pointer to support co-routimes
         | 
         | - Using our own register / calling convention (e.g. setting
         | aside a register to be available to all routines
         | 
         | - Unpicking the stack to reduce register setup for commonly
         | used routines or fast longjmps
         | 
         | - VM "jump tables" without requiring an indirection to know
         | where to jump to
        
       | unoti wrote:
       | This is the video I wished I had seen when I was a kid, feeling
       | like assembly was a dark art that I was too dumb to be able to
       | do. Later in life I did a ton of assembly professionally on
       | embedded systems. But as a kid I thought I wasn't smart enough.
       | This idea is poison, thinking you're not smart enough, and it
       | ruins lives.
       | 
       | https://youtu.be/ep7gcyrbutA?si=8HiMqH2mMwsJRNDg
        
       | boricj wrote:
       | Machine code isn't scary, but its nature is severely
       | misunderstood.
       | 
       | Skipping over the bundling of instructions into code blocks, the
       | next logical construct are functions. These have references to
       | code and data in memory; if you want to relocate functions around
       | in memory you introduce the concept of relocations to annotate
       | these references and of a linker to fix them to a particular
       | location.
       | 
       | But once the linker has done its job, the function is no longer
       | relocatable, you can't move it around... or that is what someone
       | sane might say.
       | 
       | If you can undo the work of the linker, you can extract
       | relocatable functions from executables. These functions can then
       | be reused into new executables, without decompiling them first;
       | after all, if what you've extracted is equivalent to the original
       | relocatable function, you can do the same things than it.
       | 
       | Repeat this process over the entire executable and you're
       | stripped it for parts, ready to be put back together with the
       | linker. Change some parts and you have the ability to modify it
       | as if you're replacing object files, instead of binary patching
       | it in place with all the constraints that comes with it.
       | 
       | Machine code is like Lego bricks, it just takes a rather
       | unconventional point of view (and quite a bit of time to perfect
       | the art of delinking) to realize it.
        
       | kgilpin wrote:
       | Is it enough to play Human Resource Machine!?
       | https://en.wikipedia.org/wiki/Human_Resource_Machine
       | 
       | Assembly as a game, I loved playing it.
        
         | unoti wrote:
         | > Is it enough to play Human Resource Machine!?
         | 
         | That is fun. But this one truly is enough: Turing Complete. You
         | start with boolean logic gates and progressively work your way
         | up to building your own processor, create your own assembly
         | language, and use it to do things like solve mazes and more.
         | Super duper fun
         | 
         | https://store.steampowered.com/app/1444480/Turing_Complete/
        
       | thuanao wrote:
       | I think machine code and building something like a Forth is _way_
       | easier to understand than any contemporary programming language
       | toolchain.
        
       | bitwize wrote:
       | Machine code ceased to be scary, or at least mysterious, to me
       | when I opened the rudimentary debugger on a TRS-80. It was really
       | more of a monitor, and it showed the contents of a certain chunk
       | of memory in the top half of the screen. I loaded a program I was
       | working on into it, and began changing instructions in memory,
       | using the assembler output as my guide, and jumping into the
       | program to see what the effects were. After that the little
       | lightbulb went off. Oh, these are just bytes in memory that
       | correspond to CPU instructions, and the CPU just reads them off
       | and executes the instructions.
        
       | xelxebar wrote:
       | Oh, cool. A couple years ago I spent a few days disassembling a
       | small x86-64 binary by hand. Getting familiar with the encoding
       | was a lot of fun! The following reference was indispensable:
       | 
       | http://ref.x86asm.net/
        
       | Leo-thorne wrote:
       | I always thought machine code was something only experts could
       | understand. But after reading this article, I realized the basic
       | concepts aren't that complicated, it's really just instructions,
       | registers, and memory. I feel like this has given me a clearer
       | understanding when it comes to writing code.
        
         | flohofwoe wrote:
         | Wrong article ;)
         | 
         | (I think you mean
         | https://news.ycombinator.com/item?id=44184900)
        
           | Leo-thorne wrote:
           | Thank you very much for your reminder. The comment has been
           | corrected.
        
       | Koshkin wrote:
       | Indeed. In Knuth's _Art_ the machine code was not the "scariest"
       | part. (Programming is hard.)
        
       | renox wrote:
       | The thing is: most programmers see assembly language _generated
       | by a compiler_ , so no comment, and in optimised code with vector
       | operations, it IS scary.
        
       ___________________________________________________________________
       (page generated 2025-06-05 23:02 UTC)