Hello ChatGPT

A conversation with ChatGPT about how to teach in this brave new world that contains ChatGPT. OpenAI has a public beta application called ChatGPT which is a chat-like front end to one of their large language models. It interprets what you type and generates plausible responses.

Computer, Do My Homework

ChatGPTprompt:

write a nand2tetris assembler in python

ChatGPT’s response:

# Define a dictionary that maps the binary code of each instruction
# to its corresponding mnemonic
C_INSTRUCTION_BINARY_CODES = {
    "0": "0101010",
    "1": "0111111",
    "-1": "0111010",
    "D": "0001100",
    "A": "0110000",
    "M": "1110000",
    "!D": "0001101",
    "!A": "0110001",
    "!M": "1110001",
    "-D": "0001111",
    "-A": "0110011",
    "-M": "1110011",
    "D+1": "0011111",
    "A+1": "0110111",
    "M+1": "1110111",
    "D-1": "0001110",
    "A-1": "0110010",
    "M-1": "1110010",
    "D+A": "0000010",
    "D+M": "1000010",
    "D-A": "0010011",
    "D-M": "1010011",
    "A-D": "0000111",
    "M-D": "1000111",
    "D&A": "0000000",
    "D&M": "1000000",
    "D|A": "0010101",
    "D|M": "1010101",
}

# Define a dictionary that maps the mnemonic of each jump instruction
# to its corresponding binary code
JUMP_INSTRUCTION_BINARY_CODES = {
    None: "000",
    "JGT": "001",
    "JEQ": "010",
    "JGE": "011",
    "JLT": "100",
    "JNE": "101",
    "JLE": "110",
    "JMP": "111",
}

def assemble(input_file, output_file):
  labels = {}
  ln = 0
  with open(input_file) as f:
    for line in f:
      line = line.split("//")[0].strip()
      if line:
        if line[0] == "(":
          labels[line[1:-1]] = ln
        else:
          ln += 1

  with open(input_file) as f:
    with open(output_file, "w") as out:
      for line in f:
        line = line.split("//")[0].strip()
        if line:
          if line[0] == "(":
            continue
          elif line[0] == "@":
            symbol = line[1:]
            if symbol.isdigit():
              binary = f"{int(symbol):016b}"
              out.write(binary + "\n")
            else:
              line_number = labels[symbol]
              binary = f"{line_number:016b}"
              out.write(binary + "\n")
          else:
            comp, dest, jump = line.split("=")[-1].split(";")
            cb = C_INSTRUCTION_BINARY_CODES[comp]
            db = "{:03b}".format(int(dest, 2))
            jb = JUMP_BINARY_CODES[jump]
            binary = f"111{cb}{db}{jb}"
            out.write(binary + "\n")

This is slightly revised because I asked it to rewrite the assemble function into less than 1000 bytes. In addition to the response, it gave a gentle warning that using short variable names might make the code harder to read.

But overall this is pretty close to how I would implement this functionality myself. There is a minor mistake - it does not include a dictionary of “destination” opcodes. However, a key feature of ChatGPT is you can just ask it to fix this kind of mistake, and it often can.

Can you add a dictionary for the destination opcodes?

    DEST_INSTRUCTION_BINARY_CODES = {
        None: "000",
        "M": "001",
        "D": "010",
        "MD": "011",
        "A": "100",
        "AM": "101",
        "AD": "110",
        "AMD": "111",
    }

ChatGPT in Higher Education

Our culture has created strong incentives for students to obtain STEM degrees. Sometimes these incentives outweigh their academic integrity and they resort to cheating tactics in order to succeed. In a post-ChatGPT world, what does studying look like? What does academic integrity look like?

Personally I can see the value for a tool like this - like GitHub’s CoPilot it can save a lot of time generating boilerplate code for you, so you can move past the boring parts and concentrate on the interesting parts of your problem. But I think such tools shift the emphasis on what students should learn in order to be effective in the modern world. Rather than focusing so much on syntax and programming language semantics, we may choose to offload those tasks to the chat AI. Instead, to use AI code generation effectively, we need to learn to interpret its results. We should probably focus more on testing and how to evaluate test results.

It’s a reasonable question, when you are never far from your pocket supercomputer, to ask why you should learn to answer questions that have already been answered. Why should I learn multiplication tables when I am never far from a calculator? Likewise why should I learn about parser combinators when I can simply type “implement a parser combinator in Haskell” and get a workable answer?

If only there was someone I could ask…

What questions about compilers should I ask my students so they can’t simply use ChatGPT to cheat?

There are many questions you can ask your students about compilers that would be difficult for a language model like ChatGPT to answer accurately. Here are a few examples:

What is the role of a compiler in the software development process? How does a compiler convert high-level source code into machine code? What is the difference between a just-in-time (JIT) compiler and a ahead-of-time (AOT) compiler? What are some common optimization techniques used by compilers? What are some challenges and limitations of compilers? In general, you can ask your students questions that require them to have a deep understanding of the concepts and principles of compilers, rather than just memorizing facts or being able to regurgitate information. By asking open-ended questions that require critical thinking and analysis, you can encourage your students to engage with the material in a meaningful way and discourage cheating using language models like ChatGPT.

Thanks ChatGPT, that is reasonable advice. But what if I just…

What is the role of a compiler in the software development process?

The role of a compiler in the software development process is to convert high-level source code written in a programming language into machine code that can be executed by a computer. This process is known as compilation.

During compilation, the compiler performs a number of important tasks. First, it checks the source code for syntax errors, which are mistakes in the structure of the code that would prevent it from being executed. If any syntax errors are found, the compiler will report them to the developer so they can be fixed.

Next, the compiler converts the source code into machine code, which is a low-level language that can be understood and executed by the computer’s central processing unit (CPU). This machine code is often in the form of binary instructions that the CPU can execute directly.

In addition to converting the source code into machine code, the compiler may also perform a number of optimization tasks to improve the performance of the resulting program. These tasks can include rearranging the order of instructions, eliminating unnecessary instructions, and performing other transformations that can make the program run faster or use less memory.

Overall, the role of a compiler in the software development process is to take high-level source code and produce machine code that can be executed by a computer, while also performing various optimization tasks to improve the performance of the resulting program.