Allow declarations of variables without the `var`/`let` keyword

I noticed the programming languages TensorFlow provides API's for are:

  • C++
  • Java
  • Go
  • Python
  • Swift

(Source: https://www.tensorflow.org/api_docs/)

In these languages, except in Swift, we can declare a variable without a separate keyword. Examples:

// C++
int x = 100;

// Java
int x = 100;

// Go
x := 100

# Python
x: int = 100

I propose that variables in Swift are to be implicitly declared with var when a variable-declaration keyword is missing. Examples:

// Swift
x: Int = 100    // equivalent to: `var x: Int = 100`

class C {
    p: String   // equivalent to: `var p: String`
}

Rationale:

  • The syntax will be familiar to developers coming from the other aforementioned languages which will make migrating to Swift easier.
  • The syntax will be friendlier to beginners. I've noticed people new to programming forget to add the var/let keyword when declaring their variables. Also, they mistankenly declare parameters of a function as variables.

In all of those examples except for Python, a separate syntax is still required to declare a variable. In C++ and Java, the type does double-duty as the declaration keyword. In Go, := is used to declare a variable instead of assign to an existing variable. It seems to me the same potential for forgetting the special declaration marker exists in those other languages. Python's assignment behavior is convenient for simple cases, but comes with its own share of weird scoping issues, leading to complexity elsewhere in the language with global, local, and nonlocal declarations to work around the places the implicit scoping behavior breaks down.

19 Likes

I despite languages that allow implicit var declaration because they make it super easy to miss a typo in the var name.

var foo = ""

…

doo = "something else"

…

The compiler will not complain because you use doo instead of foo and will just declare a new var.

23 Likes

Yeah -1 from me, too. This sounds just to dangerous a slope to go.

8 Likes

Swift already allows for implicit variable declaration. Since Var / Let is about accessibility. I would argue that the request is more about syntactic sugar and there should be a modifier to the ‘=‘ symbol that denotes “var” or “let”

Maybe something like this:

x = 100 // just ‘=‘ is var (mutable) as someone noted. Standard mutability applies.
x ::= 100 // is let, standard immutability applies.

The distinction has to be fairly “human readable” I would think and parseable for documentation purposes.

Just my $0.02

To be clear, I do think this is an interesting problem to contemplate. There is strong evidence that the declaration/assignment distinction is in fact confusing for a lot of programmers, especially scientific and numerics programmers, since at least one common thread among languages that have been successful in the numerics domain, going all the way back to Fortran and through Matlab, Mathematica, Numpy, and even newer ones like R and Julia, is that all of these languages don't require explicit variable declaration in the common case. I think it'd be interesting to think about how that could look in Swift, though I worry that, due to source compatibility constraints, it may be too late to do so in a satisfactory way. There is also evidence that doing it the wrong way makes it very easy to make difficult-to-notice mistakes, such as with the bizarre scoping rules of pre-strict Javascript.

1 Like

I've considered this sort of thing over the years, but am not a fan. The first thing is that we'd want to make there be a separate "assignment" and "declaration" operators, e.g. use := or something like it. This is important because you never want to allow someLongNameX = foo to accidentally declare a new variable when you wanted to reassign and meant someLongNameY = foo.

Going beyond that, Swift introduces the question of whether the assigned name is a constant or a variable. If you want to support both, you have to introduce two operators instead of one. I haven't heard anyone seriously propose that.

The most commonly suggest solution that avoids two operators is to just privilege the constant form. It is easy to argue for this, but it would also be really unfortunate to undermine the existing symmetry between let and var by introducing a new special case. This gets even more problematic if/when inout or inout var becomes a top level thing, which could happen with the ownership model.

There is also the issue that x := <some expression> is not much more compact than let x = <some expression> - so even that motivation is weak.

Finally, I don't think the argument that "other languages do this so Swift should to" is strong - there are lots of ways that Swift diverges from other languages.

Given these complexities and the low benefit to adding it, it seems like a clear -1 to me. If other folks feel similarly, I wonder if we should add this to the commonly rejected list?

-Chris

29 Likes

I wonder if we could allow this without really approving of it:

  1. Add "insert var to declare a variable" and "insert let to declare a constant" fix-its to the "use of unresolved identifier" error.

  2. Implicitly apply the "insert var" fix-it to the first use site to silence later, identical uses.

  3. Soften "use of unresolved identifier" into a warning in the REPL and playground modes.

That would keep the most casual modes from feeling frustrating for scientific developers while avoiding adding new syntax or risking dangerous mistakes in ahead-of-time compiled code.

11 Likes

What I don't get is why a simple 3 letter command is such a big problem for scientist...

4 Likes

It's not the length of the keyword that's the problem, but the semantic distinction. Declaration vs assignment is a subtle difference; in both cases, you're binding a value to a name, but with very different dynamic implications. I'm inclined to agree with @Chris_Lattner3 that a declaration-less design would be a poor fit for Swift, but it is a barrier for non-programmers getting into programming.

9 Likes

Strongly agree. “Use of unresolved identifier 'x'” is pretty cryptic to someone outside of CS. And it does nothing to explain possible remediations, which it should be doing anyway.

I also strongly agree with the feedback from this proposal. While it is a problem for people new to programming to learn the syntax of their first language, they have many bigger hurdles on their programming career. And people coming from other languages that don't have some declaration keyword(s) will just have to learn the Swift syntax (and also the semantics of the variable declarations). I don't think it's worth adding some new syntax that will require new people to the language to learn the ways deceleration can differ, not to mention everyone who already knows how it works.

1 Like

First time posting on this forum.

For me personally, learning a new language comes with certain expectations - new syntax is one of them. The burden of explicitly declaring properties as constants let or variables var was not a thing I had to overcome nor did I think of it as an “annoyance”.

Personally, I also prefer being explicit (where appropriate). In other words, given a struct or a class with multiple properties, seeing let and var declarations doesn’t require a mental pause (for lack of a better term) where this approach (subjectively) might:

let x = 42 // cool...
answer: String = "..." // pause, it's a `var`

Something to consider.

P.S. Just think about the casualties during team meetings where SwiftLint rules are discussed for this…

This would have to be -1 for me.

6 Likes

You’re implicitly assuming here that everyone who uses Swift will have a “programming career”. Many of the people who have trouble with declaration vs. assignment don’t—they have some other career that’s tangential to programming. Some of them might be interested in a programming career, but it will die early by a thousand cuts like this.

Having said that, I don’t think Swift should encourage implicitly-declared variables; I’ve worked in too many languages which have that feature to still think it’s a good idea in a large codebase. But we can at least make the diagnostics better, and perhaps we can even permit it with a warning to encourage proper style in the most casual Swift environments.

6 Likes

+1 on improving the diagnostic and adding fixits to "lead people to fix".

12 Likes

Having used languages that lack a distinction between declaration and assignment I am against this suggestion in its broader sense of many dynamic languages. However the original set of examples were really only saying that x: Int should be a shortcut for var x: Int, I have less objection to this but still don't like it. I find having a clear indicator. var\let, that this is a declaration helpful.

… and this is where Swift shoots itself in the foot, again. If Unwrap or Die taught us anything, it should be that fixits that invite being applied mindlessly will inevitably be applied mindlessly, and often inappropriately.

Regarding completely implicit declaration, it sounds like a terrible idea for Swift because Swift has hierarchical name scopes. It would be dangerous for code written at one code site to be able to change the meaning of code at a separate code site, such as:

struct ABC {
    func abc () {
        x = 1
    }
}

becoming:

struct ABC {
    x = 99 // <- the loaded gun
    ... lots of intervening declarations ...
    func abc () {
        x = 1 // <- the accidental discharge
    }
}

If there's new syntax to indicate a declaration:

  1. It doesn't really help a programmer who hasn't grasped the concept of (or the need for) declarations.
  2. let … = is hardly more onerous than … :=.
  3. I really, really like that a let/var declaration starts with syntax that clearly identifies what kind of statement it is. Syntax buried in the source code line beyond a name of random length has to be dug out and decoded.
  4. Keywords syntax-color better than punctuation.
9 Likes

That's my concern as well. Of languages with implicit declaration behavior, Python's model is probably the least bad one, where an assignment to an unqualified name always refers to a new local variable even if the name is available in an outer scope unless overridden by nonlocal or global declarations, since that limits the footgun to local scope where it has some hope of being caught by inspection or static analysis. Swift wouldn't be able to do that retroactively, though, since that'd be a major source break.

As far as fixits go, if we offer more than one suggestion, then I think we can avoid the issue of thoughtless fixit application that prompted the "unwrap or die" discussion. We already have typo detection in the compiler, which can detect and offer fixits for misspellings of variables in inner scopes. We could offer that in addition to an "add var or let to declare a new variable with this value" fixit when an assignment's left hand side fails to resolve.

2 Likes

Programming is hard. If the concept of declaring a variable before using it is too much for somebody, perhaps they should consider a career somewhere else. Anyway, I'm not at all sure that the concept of telling the compiler about the variables you want to use before you use them is really a difficult concept to get across. I remember, the first time I came across proper declarations (moving from BASIC to Pascal) my emotions were more those of irritation rather than befuddlement (why am I being forced to do this when the compiler can work it out?). However, the advantages soon changed my mind.

3 Likes

Sure, let's start fixing those cuts. Some other examples:

  • Do I need a printer to call print? That's confusing!
  • Why use mathematical jargon like Integer and Bool and not simpler words like "Whole Number" and "Question".
  • Shouldn't String? be either true or false? It is asking a question!
  • What about all the other cryptic symbols like -> [:] {} etc? Can't we just use english symbols?
  • Why I can't compile a Word file with swift code in it?
  • I made a variable public, but it doesn't appear anywhere on the Web, why is that?

Feel free to brainstorm more beginner hurdles that we can address!

4 Likes

-1 from me.

There are plenty examples of syntax in this language that I find confusing, repetitive and verbose. "let" and "var" aren't included.

If we're going to improve assignment, I'd prefer we improve the ability to assign multiple variables separated with commas. This is not presently a reliable way to organize code (because you can't mix var and let together, and because you can't use the coalescing ?? to bail a method call ), but it could be.

a: Int = 3
b: Int = 4
c: Int = 5

is not so vital when we can already do

let
a: Int = 3,
b: Int = 4,
c: Int = 5