let and var Invalid redeclaration of const in Swift REPL

本秂侑毒 提交于 2020-01-24 12:32:53

问题


In Swift REPL I can assign a constant with let, but why can I modify it later using var?

let name = "al"

var name = "bob"

Swift is not complaining here, but wasn't name a constant?


回答1:


Redeclaring a variable (in the same scope) is not valid in Swift:

$ cat test.swift 
let name = "al"
var name = "bob"

$ swiftc test.swift 
test.swift:2:5: error: invalid redeclaration of 'name'
var name = "bob"
    ^
test.swift:1:5: note: 'name' previously declared here
let name = "al"
    ^

However, the Swift REPL behaves differently:

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" 
name: String = "al"
  2> var name = "bob"
name: String = "bob"

This is intentional, as explained in Redefining Everything with the Swift REPL:

... but in the REPL interactive environment it’s useful to be able to easily make changes. The REPL was specifically designed with this kind of convenience in mind ...

... The newer definition replaces the existing definition for all subsequent references


Note: You have to enter the lines separately. If you copy those two lines into the paste buffer, start the REPL and paste them with CmdV then the result is

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" 
  2. var name = "bob"
error: repl.swift:2:5: error: invalid redeclaration of 'name'
var name = "bob"
    ^

Apparently the two statements are now evaluated in the same scope (the second line has a continuation prompt) and produce an error. The same happens with both statements in a single line:

$ swift
Welcome to Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42). Type :help for assistance.
  1> let name = "al" ; var name = "bob"
error: repl.swift:1:23: error: invalid redeclaration of 'name'
let name = "al" ; var name = "bob"
                      ^



回答2:


REPL allows re-declaration of a var or let after a var or let, if entered on a separate line.

This example is allowed in REPL but not in swiftc:

$ swift
Welcome to Apple Swift version 5.0.1 (swiftlang-1001.0.82.4 clang-1001.0.46.4).
Type :help for assistance.
 1> var x = 10
x: Int = 10
 2> let x = 20
x: Int = 20
 3> let x = 30 // allowed in REPL
x: Int = 30

You can re-let and re-var in REPL if phrases are entered line by line.

But REPL does not allow re-declarations within one line (with semicolons) or, as mentioned in an earlier answer, in pasted blocks:

 4> let y = 30; let y=20
error: repl.swift:18:17: error: invalid redeclaration of 'y'

Note also that shebang/hashbang scripts that call /usr/bin/swift will use swiftc and not the REPL. Perhaps confusingly, both swiftc and swift, as well as the REPL, are all the one and same /usr/bin/swift

#!/usr/bin/swift
let x = 10
let x = 20 // not allowed

Redeclaration of functions are allowed in the same way:

> func x() {} 
> func x() {} // allowed in REPL
> func y() {}; func y() {}  
error: repl.swift:7:19: error: invalid redeclaration of 'y()'

As we would expect, function redeclaration applies to the full function signature. Declaring an overload will declare a new function that will live alongside an existing function of the same name but with different arguments. This means that an overload will not necessarily re-declare a previous function of the same name.

Let's declare some overloading functions, and let's do so all in one line to demonstrate that they are allowed in REPL.

> func y(_:Int) {print("y Int")}; func y(_:String) {print("y String")};
> y(3) 
y Int
> y("Y") 
y String

There are two functions, and both have the same name. One takes an Int, the other a String. Let's redeclare the Int one:

func y(_:Int) {print("y Int new")};
> y(3)
y Int new

And there it is: the output shows it was re-declared.

If you are not used to captures, things can get confusing (or dangerous). Watch what happens when a variable in scope gets captured:

> var xx=10;
xx: Int = 10
> func x(){print(xx)}; x()
10

This is intuitive. But what happens when we re-declare the captured variable:

> var xx=10; x() 
10
xx: Int = 10

Everything still ok? No, wait...

> xx=20; x()
10

Why 10 and not 20? Inside x() it is still the first var xx=10 that is in scope and captured. This is how captures work. But note that the captured variable no longer exists at the REPL prompt. Redeclaring a captured variable does not get it automatically recaptured.

Sometimes I use REPL to dig into a bug or a language construct, and it is good to know about these subtleties, as they can lead to confusion as to what is happening in your code, or it can lead to misunderstandings of the language.

REPL function overloads and var/let re-declarations are all explained in the blog post mentioned in the earlier answer, see https://developer.apple.com/swift/blog/?id=20

I thought I'd summarize some of the findings from the previous answers & comments, and add some more details.



来源:https://stackoverflow.com/questions/45262283/let-and-var-invalid-redeclaration-of-const-in-swift-repl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!