83

Why is it that in nearly all modern programming languages (Go, Rust, Kotlin, Swift, Scala, Nim, even Python last version) types always come after the variable name in the variable declaration, and not before?

Why x: int = 42 and not int x = 42?
Is the latter not more readable than the former?
Is it just a trend or are there any really meaningful reasons behind this solution?

gnat
  • 21,442
  • 29
  • 112
  • 288
Andre Polykanine
  • 957
  • 1
  • 6
  • 6
  • 10
    Possible duplicate of [Why does Kotlin require type after variable, rather than before?](http://programmers.stackexchange.com/questions/311727/why-does-kotlin-require-type-after-variable-rather-than-before) – 8bittree Apr 19 '16 at 18:43
  • 3
    Yep, that's a dupe alright. Although it refers specifically to the Kotlin language, the question (and its answers) apply to all languages having this practice. – Robert Harvey Apr 19 '16 at 18:56
  • see also: [What's the rationale behind the ordering of Scala's value/variable declaration when including a type identifier?](http://programmers.stackexchange.com/questions/264509/whats-the-rationale-behind-the-ordering-of-scalas-value-variable-declaration-w) – gnat Apr 19 '16 at 19:23
  • 8
    Sorry guys, I did see the question about Kotlin when googling, but I re-asked it for not to get answers like "Because Kotlin (Go, Rust, ...) dev team decided like this". I was interested in a more common answer: why does it become kind of an epidemic? – Andre Polykanine Apr 19 '16 at 19:24
  • 3
    Hihi, so Delphi, which is (Object) Pascal, and has had types __after__ variable names since its inception, way back when in the dark ages of the previous century, is modern again ;) Btw, readability is much affected by what you are used to. Coming from Delphi, C# with its type before the var name, had me thumping my head for quite some time. – Marjan Venema Apr 20 '16 at 10:45
  • I think function types really sell this. Prefixing the types makes higher order functions really complicated to define. – Alexander Sep 22 '19 at 01:06

6 Answers6

86

All of the languages you mentioned support type inference, which means the type is an optional part of the declaration in those languages because they're smart enough to fill it in themselves when you provide an initialization expression that has an easily-determined type.

That matters because putting the optional parts of an expression farther to the right reduces parsing ambiguity, and increases consistency between the expressions that do use that part and the ones that don't. It's just simpler to parse a declaration when you know the var keyword and the variable name are both mandatory before you get to the optional stuff. In theory, all of those things which make it easier to parse for computers should improve overall readability for humans too, but that's a lot more debatable.

This argument gets especially strong when you consider all the optional type modifiers that a "non-modern" language like C++ has, such as * for pointers, & for references, const, volatile and so on. Once you throw in commas for multiple declarations, you start to get some really strange ambiguities like int* a, b; not making b a pointer.

Even C++ now supports "type on the right" declarations in the form of auto x = int{ 4 };, and it does have some advantages.

Ixrec
  • 27,621
  • 15
  • 80
  • 87
  • 2
    +1 for acknowledging the existence of mandatory keywords like `var` that provide the majority of the parsing simplification. – 8bittree Apr 20 '16 at 13:56
  • 6
    Doesn't the existence of the `var` keyword defeat the purpose of the name-first notation? I don't see the advantage of writing `var userInput: String = getUserInput()` over `String userInput = getUserInput()`. The advantage would only be relevant if `userInput = getUserInput()` is also allowed, but that would imply implicit declaraton of a scoped variable, which I find pretty abhorrent. – kdb Dec 06 '18 at 13:47
  • 4
    @kdb in languages like C# and C++ it would be `var userInput = getUserInput()` or `auto userInput = getUserInput()`, the compiler knows `getUserInput()` returns `String` so you don't have to specify it with the type deduction keyword. `userInput = getUserInput()` is of course use before declare. – Wes Toleman Apr 24 '19 at 02:20
  • @kdb the main advantage of using the `var` keyword in such a language is that you have to fix significantly less code if you change what type a function returns, as long as the rest of the code is compatible with the new type. Consider changing a returned `float` to a `double`, in most cases you wouldn't need to change anything except the declaration for the variable you're returning the value to. – Turksarama Jan 12 '22 at 23:37
  • You'd just write var userInput = getUserInput(), never mentioning that it is a String at all. In Swift, what you think is a String often is not, but just an instance of some class supporting StringProtocol, and forcing it to be a String is possible, but would be quite inefficient. – gnasher729 Mar 15 '22 at 10:32
43

Why in nearly all modern programming languages (Go, Rust, Kotlin, Swift, Scala, Nim, even Python last version) types always come after the variable declaration, and not before?

Your premise is flawed on two fronts:

  • There are new-ish programming languages that have the type before the identifier. C♯, D, or Ceylon, for example.
  • Having the type after the identifier is not a new phenomenon, it goes back to at least Pascal (designed 1968–1969, released in 1970), but actually was used in mathematical type theory, which starts ~1902. It was also used in ML (1973), CLU (1974), Hope (1970s), Modula-2 (1977–1985), Ada (1980), Miranda (1985), Caml (1985), Eiffel (1985), Oberon (1986), Modula-3 (1986–1988), and Haskell (1989).

Pascal, ML, CLU, Modula-2, and Miranda all were very influential languages, so it is not surprising that this style of type declarations stayed popular.

Why x: int = 42 and not int x = 42? Is the latter not more readable than the former?

Readability is a matter of familiarity. Personally, I find Chinese to be unreadable, but apparently, Chinese people don't. Having learned Pascal in school, dabbled with Eiffel, F♯, Haskell, and Scala, and having looked at TypeScript, Fortress, Go, Rust, Kotlin, Idris, Frege, Agda, ML, Ocaml, …, it looks completely natural to me.

Is it just a trend or are there any really meaningful reasons behind such a solution?

If it's a trend, it's pretty persistent: as I mentioned, it goes back a hundred years in mathematics.

One of the main advantages of having the type after the identifier, is that it is easy to leave the type out if you want it to be inferred. If your declarations look like this:

val i: Int = 10

Then it is trivial to leave out the type and have it inferred like this:

val i = 10

Whereas if the type comes before the identifier like this:

Int i = 10

Then it starts to get hard for the parser to distinguish an expression from a declaration:

i = 10

The solution that language designers then usually come up with is to introduce a "I don't want to write a type" keyword that has to be written instead of the type:

var  i = 10; // C♯
auto i = 10; // C++

But this doesn't actually make much sense: you basically have to explicitly write a type that says that you don't write a type. Huh? It would be much easier and more sensible to just leave it out, but that makes the grammar much more complex.

(And let's not even talk about function pointer types in C.)

The designers of several of the afore-mentioned languages have weighed in on this subject:

  • Go FAQ (see also: Go's Declaration Syntax):

    Why are declarations backwards?

    They're only backwards if you're used to C. In C, the notion is that a variable is declared like an expression denoting its type, which is a nice idea, but the type and expression grammars don't mix very well and the results can be confusing; consider function pointers. Go mostly separates expression and type syntax and that simplifies things (using prefix * for pointers is an exception that proves the rule). In C, the declaration

    int* a, b;
    

    declares a to be a pointer but not b; in Go

    var a, b *int
    

    declares both to be pointers. This is clearer and more regular. Also, the := short declaration form argues that a full variable declaration should present the same order as := so

    var a uint64 = 1
    

    has the same effect as

    a := uint64(1)
    

    Parsing is also simplified by having a distinct grammar for types that is not just the expression grammar; keywords such as func and chan keep things clear.

  • Kotlin FAQ:

    Why have type declarations on the right?

    We believe it makes the code more readable. Besides, it enables some nice syntactic features. For instance, it is easy to leave type annotations out. Scala has also proven pretty well this is not a problem.

  • Programming in Scala:

    The major deviation from Java concerns the syntax for type annotations—it's "variable: Type" instead of "Type variable" in Java. Scala's postfix type syntax resembles Pascal, Modula-2, or Eiffel. The main reason for this deviation has to do with type inference, which often lets you omit the type of a variable or the return type of a method. Using the "variable: Type" syntax this is easy—just leave out the colon and the type. But in C-style "Type variable" syntax you cannot simply leave off the type—there would be no marker to start the definition anymore. You'd need some alternative keyword to be a placeholder for a missing type (C♯ 3.0, which does some type inference, uses var for this purpose). Such an alternative keyword feels more ad-hoc and less regular than Scala's approach.

Note: the designers of Ceylon also documented why they use prefix type syntax:

Prefix instead of postfix type annotations

Why do you follow C and Java in putting type annotations first, instead of Pascal and ML in putting them after the declaration name?

Because we think this:

shared Float e = ....
shared Float log(Float b, Float x) { ... }

Is simply much easier to read than this:

shared value e: Float = .... 
shared function log(b: Float, x: Float): Float { ... }

And we simply don't understand how anyone could possibly think otherwise!

Personally, I find their "argument" a lot less convincing than the others.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
  • 8
    Seems the ability to leave out the type and still have simple parsing is granted by the addition of `var`, `auto`, `let`, or the like, not by which side of the variable the type declaration is on. `var Int x = 5` or even `Int var x = 5` could both be shortened to `var x = 5`. – 8bittree Apr 20 '16 at 13:50
  • 7
    While I fond it equally readable once you get used to it and the optional type argument is strong, I would like to point out that the IDE is not able to automatically propose variable names based on the type. I miss that when I write TypeScript. – Pierre Henry Mar 06 '18 at 13:21
  • 1
    `"Your premise is flawed on two fronts"` All of those are newer than C# or D. – Det Jul 21 '19 at 06:22
  • 6
    "But this doesn't actually make much sense: you basically have to explicitly write a type that says that you don't write a type." Well, the type-on-the-right version is exactly the same in your example... Also I disagree that it doesn't make sense. It makes exactly as much sense as `func` in Go. – Sopel Aug 13 '19 at 09:44
  • 1
    In C the declaration syntax does match the expression syntax. The C syntax "int* a, b" is not ambiguous if you associate the asterisk with the identifier ("int *a, b") , as the compiler does. Granted C++ adopted a different convention, which IMO is unfortunate because it is confusing. – Alcamtar Apr 22 '22 at 12:27
7

Pascal does it too by the way, and isn't a new language. It was an academic language though, designed from scratch.

I would say it is semantically clearer to start with the variable name. The type is just a technical detail. If you want to read your class like the model of reality that it is, it makes sense to put the names of your entities first and their technical implementation last.

C# and java stem from C so they had to respect the "prior art", so not to confuse the experienced programmer.

Martin Maat
  • 18,218
  • 3
  • 30
  • 57
  • 4
    Ada also does it that way, but Ada is most certainly not an "academic language". – John R. Strohm Apr 19 '16 at 19:27
  • Ada did it because it cribbed heavily from Pascal and Modula 2. – Gort the Robot Apr 19 '16 at 21:40
  • 2
    @StevenBurnap, a quick search reveals that Wirth's first book on Modula-2 came out in mid-1982. Ada was under development several years before that (DoD1 was in 1977 or so, as I recall), and standardized, as both an ANSI standard and a MIL-STD, in 1983. All four of the teams that submitted candidates for Ada took PASCAL as their starting points. (Bell Labs was invited by DoD to submit a candidate language based on C. They demurred, saying that C was not then and would not ever be robust enough for the DoD mission-critical software.) – John R. Strohm Apr 19 '16 at 23:30
  • I must be misremembering. I thought Wirth had been involved in Ada. – Gort the Robot Apr 20 '16 at 00:13
  • 2
    Pascal started off an academic language , but by the end of the 90s it was on the verge of being *the* language to write Windows apps in via Delphi, that is until Borland jumped the shark with pricing and left the door open for Java and C# to come and steal the prize. You'll still see a tonne of Delphi out there in legacy windows app world though. – Shayne Apr 24 '19 at 20:39
  • Pascal was also the language of choice for MacOS applications from the 1970s into the 1990s. – Jörg W Mittag Apr 22 '22 at 13:53
1

I imagine, var x : Type = value is easier for automatic refactoring than Type x = value. The former just needs to remove or add : Type between var <identifier> and =. The latter must be able to parse the entire Type expression (or semantics in the worst case) to find it.

But otherwise I don't see much of a benefit of adding a redundant var in front of declarations.

Maybe when you have large complicated or templated types I could understand that people prefer "postfix notation":

ThisIsMyLargeType[HereICome[MyType],PolicyStrategyManager]
    algorithmSettings = ...;

algorithmSettings : ThisIsMyLargeType[HereICome[MyType],PolicyStrategyManager]
    = ...

The long type (particularly without good Type naming conventions) still takes some time to be parsed by a human as a "type" in order to figure out it is a declaration. It won't matter for a compiler but if a human wants to skim code and skip declarations, it could take a moment to realize that it is a declaration after all.

I guess, a short explicit keyword just improves the ability to skim because for skipping declarations, only a fixed small keyword var needs to be read. Trained people can see faster if it is only a variable declaration and can ignore the rest.


In this light, I find Martin Maat's answer very helpful because when reading over code, one probably doesn't need to read all the type details. One can skip implementation details like type and assigned expression better when one can see the var (or val) part.

With the type after the variable name, the semantic information monotoneously transitions from unspecific to specific.

Particularly in C++, variable definitions can become streneous.


I'm pretty much used to C-like declarations which is why this is easier to read for me at the moment.


Only slightly related: the colon syntax.

Knowing Python, Nim confused me with a 2nd meaning of the colon. IMO their syntax addition of writing var x : Type does not mix well with Python syntax which already uses : as syntax delimiter. The non-Pythonic syntax changes and recommendations appear to me like an arbitrary eclecticism of different things.


The big plus of "prefix notation" is, it's much more natural to talk this way in English and related human languages. "This is my Dog Woofy." On the other hand, you could hear people say: "Do you know Johnny, the Superstar?". But for me it sounds less natural.

Could be an interesting language experiment to replace the type annoation : with "the".

Let woofy the Dog be my pet.  # var woofy : Dog = this.pet;
ChrisoLosoph
  • 151
  • 5
  • In Xcode, refactoring is never, ever text based. Instead, the source is run through the compiler, far enough to analyse its structure according to the complete language rules, then the structure is modified, and source code generated for it. If the compiler can compile it, then a refactoring tool can refactor it. – gnasher729 Mar 15 '22 at 10:38
0

Why x: int = 42 and not int x = 42? Is the latter not more readable than the former?

In such a simple example, there's not much difference, but let's make it a bit more complex: int* a, b;

This is an actual, valid declaration in C, but it doesn't do what it intuitively looks like it should do. It looks like we're declaring two variables of type int*, but actually we're declaring one int* and one int.

If your language puts the type after the variable name(s) in its declarations, that problem is impossible to run into.

Mason Wheeler
  • 82,151
  • 24
  • 234
  • 309
  • 7
    I'm not sure why moving the type declaration after would affect this. Is `x, y *int;` two `*int` or one `*int` and one `int`? Making `int*` or `*int` one token instead of two would solve it, or using an additional syntactic element like the `:`, which could work in either direction. – 8bittree Apr 19 '16 at 18:56
  • @8bittree Every language I'm familiar with that uses name-first declarations use an additional token, like `:` or `as`, between the name and the type. – Mason Wheeler Apr 19 '16 at 19:03
  • 1
    Indeed, I cannot think of a real counter example that has the type second and no separator. But there are still two distinct changes there. One could have `int*: x, y` and the ambiguity is gone while still having the type first. It's not having the type after that avoids the problem, it's the addition of the separator. – 8bittree Apr 19 '16 at 19:29
  • 3
    [Go has `x, y int` without separator.](http://blog.golang.org/gos-declaration-syntax) – Jörg W Mittag Apr 20 '16 at 12:23
  • 2
    And in Go, `x, y *int` means "declare two variables, x and y, with the type pointer-to-int". – Vatine Apr 20 '16 at 15:21
  • 14
    C# uses the prefix syntax, yet it treats `int[] x, y` as two arrays. It's just the silly C syntax which treats those modifiers as unary operators on the variable (and a mix of prefix and postfix, no less) that causes problems. – CodesInChaos Apr 23 '16 at 14:01
  • 1
    @MasonWheeler Seems like a problem with C rather than a problem with declaring type on the left. – hsym Jun 30 '21 at 09:36
0

FORTRAN used prefix notation: variables starting with I,J,K were integers. BASIC used Suffix notation: variables ending in $ were strings. Like the idea of string objects and automatic memory management, what comes around goes around: suffix notation long predates Pascal.

david
  • 275
  • 1
  • 3