84

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?

6
  • 10
    Possible duplicate of Why does Kotlin require type after variable, rather than before?
    – 8bittree
    Apr 19, 2016 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. Apr 19, 2016 at 18:56
  • 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? Apr 19, 2016 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. Apr 20, 2016 at 10:45

6 Answers 6

87

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.

6
  • 2
    +1 for acknowledging the existence of mandatory keywords like var that provide the majority of the parsing simplification.
    – 8bittree
    Apr 20, 2016 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 6, 2018 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. Apr 24, 2019 at 2: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, 2022 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, 2022 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.

5
  • 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, 2016 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. Mar 6, 2018 at 13:21
  • 1
    "Your premise is flawed on two fronts" All of those are newer than C# or D.
    – Det
    Jul 21, 2019 at 6: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, 2019 at 9: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, 2022 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.

6
  • 4
    Ada also does it that way, but Ada is most certainly not an "academic language". Apr 19, 2016 at 19:27
  • Ada did it because it cribbed heavily from Pascal and Modula 2. Apr 19, 2016 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.) Apr 19, 2016 at 23:30
  • I must be misremembering. I thought Wirth had been involved in Ada. Apr 20, 2016 at 0: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, 2019 at 20:39
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;
1
  • 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, 2022 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.

7
  • 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, 2016 at 18:56
  • 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, 2016 at 19:29
  • 3
  • 2
    And in Go, x, y *int means "declare two variables, x and y, with the type pointer-to-int".
    – Vatine
    Apr 20, 2016 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. Apr 23, 2016 at 14:01
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.

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