I'd like to know the decision behind using let key word for constants. I come from JavaScript background and in JavaScript we use const key word for a constant. I find the use of let keyword a bit unintuitive but at the same time I believe Swift team has a strong reason for using let keyword for constants.
Reaching into the haze of my memory (I couldn't find the very old thread where I remember this being talked about) I think it had something to do with let and var being the same length, so multiple variable declarations would line up nicely.
It may well be no more complicated than @harlanhaskins said, but there's also a somewhat theoretical (in the sense of: it makes no real practical difference) distinction between let and a "constant".
let's contract is that it's a variable whose value is compile-time-guaranteed not to change when accessed at run time.
That's a slightly stronger requirement than a variable whose value does not change, and a slightly different semantic than a variable whose value is known at compile time.
For example, when compiling for an executable that has read-only and read-write segments, a let variable cannot necessarily be placed in a read-only segment, since its value may need to be calculated at run-time.
For a very brief period (around two weeks), let was even replaced with val, with the following accompanying entry in the changelog:
We are renaming the let keyword to val. The let keyword didn't work out primarily because it is not a noun, so "defining a let" never sounded right. We chose val over const and other options because var and val have similar semantics (making syntactic similarity useful), because const has varied and sordid connotations in C that we don't want to bring over, and because we don't want to punish the "preferred" case with a longer keyword.
That "punish the preferred case" was a real consideration! We knew the initial audience for Swift was going to be people used to Objective-C, used to having mutability by default. We wanted them to explore getting away from that without feeling like it would be easier to "just use var". const is only two more letters, but you type letall the time in Swift, and so having it be the same length as var felt like it could end up make-or-break for tipping the scales towards immutability. We didn't know for sure, but we didn't want to sabotage ourselves. (At the same time, we also didn't feel like going as compact as Go's :=—they didn't invent this but they were the most mainstream language to use it at the time—and felt that having some keyword introducer for new names was still a good idea.) The rest is history.
By the way, JavaScript didn't have this option for naming, because JavaScript's introduction of let (more desirable scoping semantics than var) happened separately from and well before the introduction of const (enforcing immutability, with the same good scoping as let). But you can see in Swift's contemporaries the same kind of logic is there: Kotlin did go with val and var, and Rust (which was using let before Swift was) did decide to "punish" mutability by spelling it let mut and not have a short var form.
Maybe, Swift should admit the const into the fold, making it possible to define immutable variables, just like let variables, but which must be initialised at the point of declaration. However, unlike let immutable variables, their memory footprint should be the same as if they were declared as static variables.
struct Foo {
const u: Int = 32
const v: Int = 64
}
print (MemoryLayout <Foo>.stride)
// prints 1
let p = Foo ()
print (p.u)
// prints 32
// Contrast with this
struct Bar {
let u: Int = 32
let v: Int = 64
static let sv: Int = 64
}
print (MemoryLayout <Bar>.stride)
// prints 16
let q = Bar ()
print (q.sv) // error: static member 'sv' cannot be used on instance of type 'Bar'
Not the wrong tool; it is just that it forces one to spell out the type explicitly.
struct Foo {
static let u: Int = 3
}
extension Foo {
func go () {
print (Self.u)
print (Foo.u)
print (u) // error: static member 'u' cannot be used on instance of type 'Foo'
}
}
On the bright side you may have the same name u as both static and instance member.. Self.u is a good compromise to not spell the type name explicitly.
I'm thinking that we already have type alias as defined below. Similarly we can have an alias for the keyword let so that while passing the code to the compiler, it replaces const with let in the AST and helps in backward compatibility.
You may also use dynamic property var u: Int { 3 } - that won't take space and doesn't require type/Self prefixing.
We only have typealias... No keywordalias that would be required here to redefine let into const, and not even a closer concept of varalias / funcalias (e.g. to be able calling func foo() via the name bar())