57

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?

  • 10
    Possible duplicate of 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
  • 2
    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
  • 2
    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
64

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.

  • 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
  • 2
    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 6 '18 at 13:47
  • 2
    @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 at 2:20
32

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.

  • 4
    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
  • 5
    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 6 '18 at 13:21
  • "Your premise is flawed on two fronts" All of those are newer than C# or D. – Det Jul 21 at 6:22
  • 3
    "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 at 9:44
4

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.

  • 3
    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 0:13
  • 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 at 20:39
1

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.

  • 4
    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
  • 3
  • 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
  • 10
    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

Not the answer you're looking for? Browse other questions tagged or ask your own question.