Search code examples
swiftread-eval-print-loop

How do the Swift REPL and the swiftc compiler interpret the language differently?


Swift has a compiler (swiftc) and a REPL. I like using the REPL to learn and play with language constructs.

In one of my experiments I came across a notable difference w.r.t how "let" works.

The following is, as I would expect, not allowed in swiftc, but the REPL allows it.

let x = 10
let x = 20 // ok in REPL

And now I am wondering what other differences there are. Are they documented anywhere?


Solution

  • In a REPL environment, you'd want to be able to redeclare variables, right? Otherwise, as you keep using the REPL, and you declare more and more variables, let constants, functions, classes, whatever, you'll run out of names to use!

    For example, let's say you want to try out string interpolation:

    let x = 10
    print("x is \(x)!")
    

    And then a while later, you learn about string concatenation, and you want to try that out as well. At this point, you'd want to be able to redeclare a let constant x, right?

    let x = "A"
    let y = "B"
    print(x + y)
    

    You could argue that you could use a or b, but as time goes on, you'll slowly run out of names. REPL is designed like this so that you don't have to restart the REPL very frequently.

    So each time you submit something, previously declared symbols that are also declared in the submission will get overwritten. This is documented here.

    swiftc has a completely different use case - you usually use it to compile larger programs, with more than just a few lines of code. In these situations, the global scope will have a lot less symbols, and redeclaring variables isn't really practical to implement, because the code execution isn't linear from top to bottom. There could be multiple files as well that talk to each other. How do you figure out what redeclares what? It just doesn't make sense to do this in anywhere other than a REPL.

    Other REPLs have this feature too, like csharppad.com for C#, ghci for Haskell, and python, just to name a few. So it's really just a common thing you do when you implement REPLs, not something special to Swift.

    In fact, you can reproduce the swiftc behaviour in a REPL by writing the two lines in a function, because now the two lines are in the same submission, and will not overwrite each other.