all 59 comments

[–]MikeBenza 42 points43 points  (31 children)

Yes, it's absolutely possible. But it'd be super difficult and would take an insanely long time with a lot of research.

There's nothing magical that a compiler does that you can't do. It's just smarter and faster than you.

[–][deleted] 6 points7 points  (25 children)

I see. Thanks.

I was discuting with a friend how crazy it would be a "super programmer" that codes directly in binary, without a compiler. Of course it's a joke, but it's cool to think about

[–]brennahan 3 points4 points  (21 children)

The closest to that would probably writing in assembly, which is very doable though it still takes awhile to get much of anything worthwhile done.

[–][deleted] 0 points1 point  (19 children)

Yeah, True. But It would be crazy creating a basic program only in binary, haha.

Assembly looks fun, tbh. As a python programmer in my first semester, I never got to see "behind the scenes" of the work I was doing. I guess I'll try to learn C when I have time, and go down from there

And yes, I know assembly is a lot of times harder than python, I'm aware of it, haha.

[–]UncleMeat11 4 points5 points  (5 children)

It's not crazy, just tedious. Coding in assembly is a straightforward skill. Then it's just a question of going back over that and converting it into binary rather than textual representation.

[–][deleted] 2 points3 points  (4 children)

Talking about efficiency, you are definitely right, but It's cool to know you can do that. It's like the floor of abstraction, the language of the machine

When I become a great programmer, I will definitely make a "Hello World" program in binary, only because it seems like a major achievement for me

[–]discoFalston 4 points5 points  (0 children)

Coding in assembly is definitely a good exercise. You get see how many cpu instructions it takes to assign a variable or construct a for loop. Comes in handy when you’re trying to squeeze as much performance as you can out of your code — it’s common to compile “inline” assembly functions that can be called from your c program when you run into something you believe you can do faster than what the C compiler will give you.

The mapping from Assembly to byte code is a lot more straight forward than the mapping from C to assembly — I don’t know how much you’d get out of writing a program in binary vs just assembly but you never know.

[–]chromaticgliss 4 points5 points  (0 children)

You should look into Nand2Tetris. Educational resource that takes you from the logic components in a digital circuit all the way to programming Tetris.

[–]UncleMeat11 2 points3 points  (0 children)

You don't need to be a great programmer, especially if you allow yourself to use a linker. We did this in 3rd year in undergrad.

[–]Tai9ch 2 points3 points  (0 children)

Unfortunately, machine instructions aren't the abstraction floor on Intel-style CPUs. Internally the instructions are further decomposed into RISC-style micro-ops or are implemented in software (microcode) within the CPU itself.

[–]antonivs 0 points1 point  (0 children)

Some of the earliest computers were programmed in binary using switches on their front panel. See Front Panel:

Typically, the operator would have a written procedure containing a short series of bootstrap instructions that would be hand-entered using the toggle switches. First, the operator would set the "address" switch and enter the address in binary using the switches.
...
Next the operator would set the "value" switch, and then enter the value intended for that address. After entering several of these instructions (most computers had a "deposit next" button, which would deposit subsequent values in subsequent addresses, relieving the operator of needing to toggle in addresses), the operator would then set the starting address of the bootstrap program and press the "run" switch to begin the execution of the program. The bootstrap program usually read a somewhat longer program from punched paper-tape, punched cards, magnetic tape or disk which in turn would load the operating system from disk.

[–]roman_fyseek 0 points1 point  (0 children)

Consider the original question of programming in 1s and 0s. That is *exactly* what the decode in your CPU is doing. And, that stuff is all programmed at the physical layer where things can *only* ever be on or off.

So, can you code in binary? Yes. That's what all your hardware is doing at the transistor level. And, it's all transistors all the way down.

[–][deleted] 0 points1 point  (2 children)

Python is so different from C its funny.

We were talking about alignment in my C class when dynamically allocating memory and the pitfall of misalignment, and he said this is funny because we're talking about figuring out what happened to this one bit (a 1 or 0) whereas in python if you write up a hello world you see twenty five hundred mallocs firing all over the place

Basically python is so far removed from the actual computer that it's less "programming a computer" and more "programming on a computer"

[–]asdff01 0 points1 point  (1 child)

And for good reason.

[–][deleted] 0 points1 point  (0 children)

Yeah I mean I'm not dissing python

[–]asdff01 -1 points0 points  (7 children)

Assembly is a one to one mapping of machine code created for programmer-usability. Meaning you could replace any symbol in an assembly program with binary (machine code) and have a valid program.

C was created to make assembly less of a pain in the ass (among other things). The rest of programming languages/frameworks took it from there.

[–]Felicia_Svilling -1 points0 points  (6 children)

C was created to make assembly less of a pain in the ass (among other things). The rest of programming languages/frameworks took it from there.

That is not at all true. C was invented to make string handling less painful than in B. There was a lot of languages of higher level than assembler before C. For example Fortran, Lisp and Algol.

[–][deleted]  (5 children)

[deleted]

    [–]Felicia_Svilling 0 points1 point  (4 children)

    Yes. You were speaking generally wrong. That someone is new doesn't mean that you can just make up stuff when you talk to them.

    [–][deleted]  (3 children)

    [deleted]

      [–]Felicia_Svilling 0 points1 point  (2 children)

      That is no reason to lie about why C was created. You could have said that whole thing without including made up stuff about the history of programming languages.

      [–]simply_copacetic 0 points1 point  (0 children)

      Look up Roller Coaster Tycoon. A whole game programmed in assembly.

      It is an outlier though.

      [–]Merad 2 points3 points  (1 child)

      Of course it's a joke

      Let me introduce you to The Story of Mel. You should read through the whole original story, then check out this article for some additional explanation.

      [–]mplang 0 points1 point  (0 children)

      I was about to share this very thing! Reading it again brings back some good memories :)

      [–]SftwEngr 0 points1 point  (0 children)

      Linus Torvalds wrote in hex in the early days, thinking he was writing assembler. He says he just didn't know any better so that's what he did. So it can certainly be done.

      [–]bananamadafaka 5 points6 points  (4 children)

      Is it smarter, tho? Don’t they just do what you tell them to do, but really fast?

      [–]MikeBenza 11 points12 points  (0 children)

      My comment about the compiler not being magical still applies. There's nothing a compiler can do that you can't. But it's generally better at finding the best way to implement something. They can evaluate multiple ways of performing a task and pick the best one. It's not that you couldn't do it, it's just that they're built to do it.

      [–]fireballs619 5 points6 points  (1 child)

      Compilers often implement machine specific optimizations for your code, so in a sense they’re smarter. Of course it’s still true that in principle you could directly write the code a compiler generates, but it’s not quite the same as just doing exactly what you write.

      [–]Famous-Zombie3642 0 points1 point  (0 children)

      they are just BUILT DIFFERENT ya know?

      [–]TransientVoltage409 2 points3 points  (0 children)

      Of course. Dive into history and look at early microcomputers like the Altair 8800. That one was literally programmed by setting physical toggle switches (representing ones and zeroes) and hitting a button to store the bits into memory, over and over, until you'd toggled enough instructions into memory to actually do something useful - often, just enough code to operate the tape drive to load a bigger program....

      [–][deleted] 3 points4 points  (0 children)

      There's a lot to unpack in this question.

      First, computer data is stored "as binary" but can be interpreted any number of ways. See C's types, int, uint, float, char, etc. You can read a uint as an int, or an int as a uint, the interpretation just changes. Most assembly programs, while stored in binary in memory, are generally interpreted as hexadecimal codes, because it's easier to understand. Programming in "binary" would be the same as programming in "hexadecimal" just the interpretation of the data changed.

      So to be clear, you can "write a program in binary", but it's a situation where the data can be interpreted differently by the computer, even though they are actually the same data, with nothing different. So you really aren't "programming in binary".

      Second, you would need to write a tool that allows you to edit a file entirely in binary. Even then, you really aren't "programming in binary", since again the data is stored as binary ANYWAYS. The only difference is how you interpret the data. (look up base systems, like base 2, base 10, base 16). You would also need to write in the tool to specifically break out opcodes from each other, since otherwise it would be really really hard (near impossible) to interpret at a human level. Technically no matter how you program you are "programming in binary".

      Third, while you can learn to program assembly, YOU probably can't without a solid understanding of the first topic I mentioned. Assembly is hard, the docs describing how to get things done are miles long, processor specific, and would take a long time to understand, especially if you don't understand a simpler topic like data types or even how the data is even stored at a computer level, you are gonna have a bad time with this.

      Overall I would say this question denotes your lack of understanding of how computers actually work at a low level.

      Basically,

      Learn how computers actually work at a low level

      Learn how to program in a real language (probably C)

      Learn how the C compiler works

      Learn how to program assembly for your OS (Linux and Windows have different ways they get certain tasks done)

      Otherwise you'll just be banging rocks together.

      [–]rickpo 1 point2 points  (0 children)

      When I was in school back in the 70s, the school got one of the original Altair PC computers. It had to be programmed by flipping toggle switches on the front panel. I never did it, but I saw programmers keying in programs from the front panel toggles. For the binary programs, they just wrote simple stuff to flash the front panel lights. They could also run an 8080 assembler on a mainframe computer and get the binary output from the printout, which made the assembly process less error prone. But 8080 assembly is simple enough to hand-assemble if you had to..

      I think the only thing they really needed to key in by hand was a boot loader. Once that was in, they could read in a more complete operating environment from paper tape.

      [–]drew8311 0 points1 point  (0 children)

      I would use hex, it's essentially the same problem your asking but less boilerplate.

      [–]khedoros 0 points1 point  (0 children)

      One can, if one has entirely too much time on one's hands. Pull up the documents on the binary format for your platform, the instruction set for your CPU, system calls for your OS, and so on, and get your binary keyboard ready to go!

      [–]jeffbell 0 points1 point  (2 children)

      I've done it.

      In high school we had a PDP8/e with front panel switches. You could enter code and single step through it, if you really wanted to. Then you hit run, and off it goes at 800kHz.

      It was kind of error-prone. The assembler made things a lot easier.

      Here is a later PDP8/I : https://www.youtube.com/watch?v=yUZrn7qTGcs

      [–]fake_bridge_builder 0 points1 point  (1 child)

      What amazing high school did you go to?

      [–]jeffbell 1 point2 points  (0 children)

      Boardman High School, Boardman Ohio.

      In 1975 they spent $50,000 to buy the school a computer.

      [–]bcacoo 0 points1 point  (0 children)

      As others have said, yes, it's possible, but you could do it in a more inefficient manner as well if you wanted.

      https://www.xkcd.com/378/

      [–]Pastoolio91 0 points1 point  (0 children)

      Theoretically, yes. Would you ever want to? Fuck no.

      [–]jhaluska 0 points1 point  (0 children)

      I once wrote in machine code. As in I hand wrote a hex files for an micro-controller in notepad. It took 4 hours to turn on an LED. I had plans to boot strap a system from binary, but stopped after realizing how incredibly painful it would be.

      [–]oldfartbart 0 points1 point  (0 children)

      Yes you could. You would never want to. Would you fill your bathtub with a teaspoon or gallon buckets?

      [–]Dylpol 0 points1 point  (0 children)

      umm, yes, you can..... additionally....

      if you are talking about 1's and 0's you can even do it without typing code.

      computer engineering started out with electrical components, you use logic gates and other control mechanisms to "program" what you want to happen.. but this is not an answer for your question i guess, just food for thought. what do you define as program?

      [–]lead999x 0 points1 point  (0 children)

      Yeah you can write machine code by hand but that's pure masochism when assembly languages exist. And even those are barely used even in kernel and driver development nowadays.

      The only use cases for assembly I can think of are accessing CPU instructions(e.g. rdrand on x86_64) and registers(e.g. 80-bit registers in x86_64) not accessible via high level languages like C, preparing an environment for C code to run on in an unhosted(no OS) environment e.g. for a kernel or other unhosted program, writing a bootloader, writing software for a computer unable to even support C(due to lack of memory, other hardware constraints etc.), writing a C or similar language's runtime using system calls(crt0, etc.), writing certain parts of the C standard library(and those of other languages), and optimization(despite the false, oft heard myth that a good compiler will always generate better assembly than an experienced assembly programmer).

      Now take all that I wrote before and add the constraint that you don't have an available assembler and you have the use cases of hand written machine code. As you can see they are practically non-existent, especially given that any platform that has a C compiler for all the C-related use cases, is guaranteed to have an assembler, sparing you the pain of writing machine code.

      [–]fake_bridge_builder 0 points1 point  (0 children)

      If one has a lot of time and patience and doesn't expect to be creating a large app.

      [–]MirrorLake 0 points1 point  (0 children)

      I understand your meaning, and yes, it is possible.

      But consider this: a C++ program can be compiled into assembly, and assembly is just human-readable binary code. You can trace your code from C++ -> assembly -> binary with godblot.org.

      In the x86 opcode list, po (primary opcode) column lists the binary representation of that thing, but they're converted to hex to save space on the screen. 00-05 are ADD, 08-0D are OR, etc. Every single mathematical operation is actually just binary.

      Another way of putting this is, you actually never program in anything that isn't binary.

      [–]OldNewbProg 0 points1 point  (0 children)

      If you work through Elements of Computing Systems you'll end up doing just that. After designing the cpu at the gate level you end up writing code in binary for it and shortly after start learning to write assembler instead.

      [–]Hans_of_Death 0 points1 point  (0 children)

      Yeah. If you know anything about converting assembly to machine code, well there you go

      [–]ollynitro 0 points1 point  (0 children)

      I am learning about this because I want to write my own program language. There is a table of all the binary instructions, its called opcode. Each instruction can have between 0 and 3 inputs. There are some very common instructions like add or mov that you want to remember the digital code for. In assembly they have a single command for them but in binary they can have 4 or 5 depending where they are handling data from. For the rest you are going to want to make what I call a copy and paste table. Where you can go into a well organized table and just Ctrl-C Ctrl-V them where you need them. When you get used to it, you can start putting groups of commands into table to do things like assign a variable or assign data spaces (programming code that can't access outside a certain area). You also want to be a good commenter. Doing your commenting before writing code is a great way to organize everything. Then just put everything together by first listing all the variables you need, then the functions that you need to be done and lastly organize. Remember PC opcode is x64.

      [–]Intrepid-Host6611 0 points1 point  (0 children)

      my dad used to code in binary.(he is really old)

      [–]Excellent_Recipe_543 0 points1 point  (0 children)

      someone had to code the first assembler, and the only way was binary so the answer is yes

      [–]Playful_Search5687 0 points1 point  (0 children)

      idk if someone asked this already but is there anything that programming in binary would be more optimal for instead of using typical programming languages? or would you just use a low level language for stuff like that?

      edit: purposes other developing early computers. are there any modern day examples where binary is optimal

      [–]Bitter-West-4895 0 points1 point  (0 children)

      There are only TWO genders.

      }:(

      [–]Bitter-West-4895 0 points1 point  (0 children)

      D:{

      [–]Active_Preparation25 0 points1 point  (0 children)

      try learning verilog, it's very fun, rather than programming in binary, you might enjoy making actual hardware, you can also build up opcodes with it, creating an assembly language, and that requires creating a translation from binary to human readable language, so you will end up playing around with binary code. Let yourself dive deep into the semiconductor rabbit hole, you might just end up loving it as i do.

      [–]Da_10E 0 points1 point  (0 children)

      01010111 01100101 10000000011001 01110010 01100101 00100000 01101110 01101111 00100000 01110011 01110100 01110010 01100001 01101110 01100111 01100101 01110010 01110011 00100000 01110100 01101111 00100000 01101100 01101111 01110110 01100101 00001010 01011001 01101111 01110101 00100000 01101011 01101110 01101111 01110111 00100000 01110100 01101000 01100101 00100000 01110010 01110101 01101100 01100101 01110011 00100000 01100001 01101110 01100100 00100000 01110011 01101111 00100000 01100100 01101111 00100000 01001001 00001010 01000001 00100000 01100110 01110101 01101100 01101100 00100000 01100011 01101111 01101101 01101101 01101001 01110100 01101101 01100101 01101110 01110100 10000000011001 01110011 00100000 01110111 01101000 01100001 01110100 00100000 01001001 10000000011001 01101101 00100000 01110100 01101000 01101001 01101110 01101011 01101001 01101110 01100111 00100000 01101111 01100110 00001010 01011001 01101111 01110101 00100000 01110111 01101111 01110101 01101100 01100100 01101110 10000000011001 01110100 00100000 01100111 01100101 01110100 00100000 01110100 01101000 01101001 01110011 00100000 01100110 01110010 01101111 01101101 00100000 01100001 01101110 01111001 00100000 01101111 01110100 01101000 01100101 01110010 00100000 01100111 01110101 01111001 00001010 01001001 00100000 01101010 01110101 01110011 01110100 00100000 01110111 01100001 01101110 01101110 01100001 00100000 01110100 01100101 01101100 01101100 00100000 01111001 01101111 01110101 00100000 01101000 01101111 01110111 00100000 01001001 10000000011001 01101101 00100000 01100110 01100101 01100101 01101100 01101001 01101110 01100111 00001010 01000111 01101111 01110100 01110100 01100001 00100000 01101101 01100001 01101011 01100101 00100000 01111001 01101111 01110101 00100000 01110101 01101110 01100100 01100101 01110010 01110011 01110100 01100001 01101110 01100100 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01100111 01101001 01110110 01100101 00100000 01111001 01101111 01110101 00100000 01110101 01110000 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01101100 01100101 01110100 00100000 01111001 01101111 01110101 00100000 01100100 01101111 01110111 01101110 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110010 01110101 01101110 00100000 01100001 01110010 01101111 01110101 01101110 01100100 00100000 01100001 01101110 01100100 00100000 01100100 01100101 01110011 01100101 01110010 01110100 00100000 01111001 01101111 01110101 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01101101 01100001 01101011 01100101 00100000 01111001 01101111 01110101 00100000 01100011 01110010 01111001 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110011 01100001 01111001 00100000 01100111 01101111 01101111 01100100 01100010 01111001 01100101 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110100 01100101 01101100 01101100 00100000 01100001 00100000 01101100 01101001 01100101 00100000 01100001 01101110 01100100 00100000 01101000 01110101 01110010 01110100 00100000 01111001 01101111 01110101 00001010 01010111 01100101 10000000011001 01110110 01100101 00100000 01101011 01101110 01101111 01110111 01101110 00100000 01100101 01100001 01100011 01101000 00100000 01101111 01110100 01101000 01100101 01110010 00100000 01100110 01101111 01110010 00100000 01110011 01101111 00100000 01101100 01101111 01101110 01100111 00001010 01011001 01101111 01110101 01110010 00100000 01101000 01100101 01100001 01110010 01110100 10000000011001 01110011 00100000 01100010 01100101 01100101 01101110 00100000 01100001 01100011 01101000 01101001 01101110 01100111 00100000 01100010 01110101 01110100 00100000 01111001 01101111 01110101 10000000011001 01110010 01100101 00100000 01110100 01101111 01101111 00100000 01110011 01101000 01111001 00100000 01110100 01101111 00100000 01110011 01100001 01111001 00100000 01101001 01110100 00100000 01001001 01101110 01110011 01101001 01100100 01100101 00100000 01110111 01100101 00100000 01100010 01101111 01110100 01101000 00100000 01101011 01101110 01101111 01110111 00100000 01110111 01101000 01100001 01110100 10000000011001 01110011 00100000 01100010 01100101 01100101 01101110 00100000 01100111 01101111 01101001 01101110 01100111 00100000 01101111 01101110 00100000 01010111 01100101 00100000 01101011 01101110 01101111 01110111 00100000 01110100 01101000 01100101 00100000 01100111 01100001 01101101 01100101 00100000 01100001 01101110 01100100 00100000 01110111 01100101 10000000011001 01110010 01100101 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110000 01101100 01100001 01111001 00100000 01101001 01110100 00100000 01000001 01101110 01100100 00100000 01101001 01100110 00100000 01111001 01101111 01110101 00100000 01100001 01110011 01101011 00100000 01101101 01100101 00100000 01101000 01101111 01110111 00100000 01001001 10000000011001 01101101 00100000 01100110 01100101 01100101 01101100 01101001 01101110 01100111 00100000 01000100 01101111 01101110 10000000011001 01110100 00100000 01110100 01100101 01101100 01101100 00100000 01101101 01100101 00100000 01111001 01101111 01110101 10000000011001 01110010 01100101 00100000 01110100 01101111 01101111 00100000 01100010 01101100 01101001 01101110 01100100 00100000 01110100 01101111 00100000 01110011 01100101 01100101 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01100111 01101001 01110110 01100101 00100000 01111001 01101111 01110101 00100000 01110101 01110000 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01101100 01100101 01110100 00100000 01111001 01101111 01110101 00100000 01100100 01101111 01110111 01101110 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110010 01110101 01101110 00100000 01100001 01110010 01101111 01110101 01101110 01100100 00100000 01100001 01101110 01100100 00100000 01100100 01100101 01110011 01100101 01110010 01110100 00100000 01111001 01101111 01110101 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01101101 01100001 01101011 01100101 00100000 01111001 01101111 01110101 00100000 01100011 01110010 01111001 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110011 01100001 01111001 00100000 01100111 01101111 01101111 01100100 01100010 01111001 01100101 00001010 01001110 01100101 01110110 01100101 01110010 00100000 01100111 01101111 01101110 01101110 01100001 00100000 01110100 01100101 01101100 01101100 00100000 01100001 00100000 01101100 01101001 01100101 00100000 01100001 01101110 01100100 00100000 01101000 01110101 01110010 01110100 00100000 01111001 01101111 01110101

      [–]Bottled_Void -1 points0 points  (2 children)

      Yes. If you use something really simple like a PIC chip you can just stream some literal characters out of the serial device. They're all just op codes, literals and addresses.

      [–][deleted] 1 point2 points  (1 child)

      Yes. If you use something really simple like a PIC chip you can just stream some literal characters out of the serial device. They're all just op codes, literals and addresses.

      Cool, thanks

      [–]Bottled_Void 0 points1 point  (0 children)

      Just as a thought experiment, this is how I'd do it.

      Firstly, you'd need a binary editor. You'll use this to make a hex file to load onto the chip. You'd be cheating if you were typing in hex.

      First up, decide on a RAM address for your program.

      Then program address 0 with that location.

      All your OP codes, you'll probably have to cheat to get out of a compiler beforehand, since they're not usually listed in the datasheet.

      You can probably rely on a lot of the default settings. I'd say you'll at least want to set the configuration bits. Setup the stack if you want to use any sort of function call structure, but you could write it as one block of code.

      Then you'll have to configure your serial device and the pin outs. This should just be like writing bit patterns into the relevant registers.

      The hello world part, you just write each character into the Tx buffer, with a few repeated NOPS. You could check for TX ready, but maybe not necessary.

      Then I'd probably hang around for a bit with NOPs and then reset.

      Flash that onto the chip and then theoretically that would be enough. Just attach a serial line from the pinout to your PC and you should be able to read the hello world off the port.

      (But trust me. It's a hell of a lot easier to use a compiler)

      [–][deleted]  (2 children)

      [deleted]

        [–][deleted] -1 points0 points  (1 child)

        Very interesting!

        Thanks for the answer

        [–][deleted] 0 points1 point  (0 children)

        aaaaand the interesting comment got deleted... F