The first programs were written in binary/hexadecimal, and only later did we invent coding languages to convert between human readable code and binary machine code.

So why can’t we just do the same thing in reverse? I hear a lot about devices from audio streaming to footware rendered useless by abandonware. Couldn’t a very smart person (or AI) just take the existing program and turn it into code?

  • Fondots@lemmy.world
    link
    fedilink
    arrow-up
    13
    ·
    5 months ago

    To build on/give some example about what you said with the comments and function names (programmers, excuse the sloppy pseudocode that’s about to follow, it’s been a long time since high school intro to computer science)

    Let’s say in a video game, you run around collecting coins, and if you get 100 coins you earn an extra life

    One small part of that code may look something like:

    IF
    newGame = TRUE
    THEN
    coinCount = 0
    lifeCount = 3
    coinModel.all.visibility = TRUE
    //Players start a new game with 3 lives and 0 coins, and all coins are visible in the level

    IF
    playerModel.isTouching.coinModel.x = TRUE
    THEN
    coinModel.x.visibility = FALSE
    coinCount++
    //If the player character model touches one of the coin models, that coin model disappears, and the players coin count is increased by 1
    IF
    coinCount % 100 = 0
    THEN
    lifeCount++
    //if that coin count is divisible evenly by 100, then the players life count is also increased by 1

    Quick notes for people who have even less programming background than me

    ++ Is used by a lot of programming languages to increase a value by 1

    % is often used as the “modulo” operator, which basically returns the remainder from division. So 10 % 2 = 0, because 10 is evenly divisible by 2, 10 % 3 = 1, because 10 is divisible by 3 but not evenly and leaves a remainder of 1

    // Are comments, they don’t affect the code, they’re just there for human readability to make it more understandable, so you can explain why you did what you did for anyone who has to maintain the code after you, etc.

    Hopefully, between the simple variable names and comments, those pseudocode blocks all pretty readable for laypeople, but if not

    The first block basically detects if you’re starting a new game (IF newGame = TRUE)
    If it is, then it resets your life counter to a default 3, and you start with 0 coins and sets all of the coins in the level to be visible so you can collect them
    Otherwise it would carry over the values from your previous level, or save game, or whatever

    The second block detects if you touch a coin (playerModel.isTouching.coinModel.x = TRUE) If you do, that coin vanishes (coin.x.visibility = FALSE)
    It also increases your coin count (coinCount++)
    Then if your coin count is divisible evenly by 100 (coinCount % 100 = 0) it increases your life total (lifeCount++)

    When the code gets compiled, that gets turned into machine code, basically all 1s and 0s that the computer can understand. The computer doesn’t care if you call a coin a coin or if you call it object1, it’s going to strip all of those human-readable elements out because it would just be a waste of storage and processing power to keep it in.

    So when you recompile that, you don’t get any of the explanatory comments or the easy to read variable names, so you might end up with something looking kind of like this

    IF
    Variable1 = TRUE
    THEN
    Variable2 = 0
    Variable3 = 3
    object1.all.condition1 = TRUE

    IF
    object2.condition2.object1.x = TRUE
    THEN
    object1.x.condition1 = FALSE
    variable2++
    IF
    variable2 % 100 = 0
    THEN
    variable3++

    Which is a lot harder to understand. The code will still work, you could recompile it and run it, but if you want to make any changes, you’d basically need to comb through it, figure out what all the variables, objects, conditions, etc. are, and try to piece together why the programmers who originally wrote the code did it the way they did

    And that’s of course a bit of an oversimplification, for various reasons it may not decompile and recompile exactly 1:1 with the original code, it’s almost like translating the same sentence back and forth between 2 languages with Google translate.

    And even this little snippet of fairly simple and straightforward code would probably going to be backed up by dozens, if not hundreds or thousands of other lines of code just to make this bit work, defining what a coin is, the hit boxes, animations, how it determines if it’s a new game or or continuing a previous game, etc.

    • Emily (she/her)@lemmy.blahaj.zone
      link
      fedilink
      arrow-up
      14
      ·
      edit-2
      5 months ago

      Thank you for adding this! If people want a real life example of the effect shown in this pseudocode, here is a side-by-side comparison of real production code I wrote and it’s decompiled counterpart:

          override fun process(event: MapStateEvent) {
              when(event) {
                  is MapStateEvent.LassoButtonClicked -> {
                      action(
                          MapStateAction.LassoButtonSelected(false),
                          MapStateAction.Transition(BrowseMapState::class.java)
                      )
                  }
                  is MapStateEvent.SaveSearchClicked -> {
                      save(event.name)
                  }
                  // Propagated from the previous level
                  is MapStateEvent.LassoCursorLifted -> {
                      load(event.line + event.line.first())
                  }
                  is MapStateEvent.ClusterClick -> {
                      when (val action = ClusterHelper.handleClick(event.cluster)) {
                          is ClusterHelper.Action.OpenBottomDialog ->
                              action(MapStateAction.OpenBottomDialog(action.items))
                          is ClusterHelper.Action.AnimateCamera ->
                              action(MapStateAction.AnimateCamera(action.animation))
                      }
                  }
                  is MapStateEvent.ClusterItemClick -> {
                      action(
                          MapStateAction.OpenItem(event.item.proposal)
                      )
                  }
                  else -> {}
              }
          }
      

      decompiled:

          public void c(@l j jVar) {
              L.p(jVar, D.f10724I0);
              if (jVar instanceof j.c) {
                  f(new i.h(false), new i.r(c.class, (j) null, 2, (C2498w) null));
              } else if (jVar instanceof j.e) {
                  m(((j.e) jVar).f8620a);
              } else if (jVar instanceof j.d) {
                  List<LatLng> list = ((j.d) jVar).f8619a;
                  j(I.A4(list, I.w2(list)));
              } else if (jVar instanceof j.a) {
                  d.a a7 = d.f8573a.a(((j.a) jVar).f8616a);
                  if (a7 instanceof d.a.b) {
                      f(new i.j(((d.a.b) a7).f8575a));
                  } else if (a7 instanceof d.a.C0058a) {
                      f(new i.a(((d.a.C0058a) a7).f8574a));
                  }
              } else if (jVar instanceof j.b) {
                  f(new i.k(((j.b) jVar).f8617a.f11799a));
              }
          }
      

      keep in mind, this was buried in hundreds of unlabeled classes and functions. I was only able to find this in a short amount of time because I have the most intimate knowledge of the code possible, having written it myself.