Proposal: Make ':=' the standard declaration operator in Mojo (Go-style)

Hi Mojo team and community,

There have been discussions about assignment syntax and whether Mojo should adopt Python’s walrus operator (:=). Some voices have even suggested removing = entirely.

I believe there is a much cleaner path forward, inspired by Go (Golang).

Go’s Success Story

In Go, the short declaration operator := has become the default and idiomatic way to declare and initialize variables inside functions. Most Go code uses := for the vast majority of local variable declarations. The regular = is used only for reassignment to already-declared variables.

This approach has worked extremely well for over 15 years.

Important clarification: Go is not a scripting language. It is a statically typed, compiled systems programming language used at Google, Uber, Dropbox, Kubernetes, Docker, and many other high-performance projects. The success of := has nothing to do with “scripting language stupidity” — it is a deliberate, thoughtful language design decision.

Why Python’s Walrus Operator Was So Controversial

When Python introduced the walrus operator (:=) in 3.8 as an assignment expression, it caused massive controversy, including contributing to Guido van Rossum temporarily stepping down as BDFL.

The main objections were:

  • It broke Python’s long-standing rule that assignment (=) is a statement, never an expression.
  • It introduced inconsistency by creating two similar-looking assignment operators with different rules.
  • Many felt it sacrificed Python’s core philosophy of “Explicit is better than implicit” and “Readability counts”.

The walrus operator was introduced primarily to prevent a dangerous class of logical bugs: the classic mistake of writing = instead of == inside conditions:

if (x = 5):      # Accidentally assigns instead of comparing → always True!

In C/C++ this bug has caused countless subtle logic errors that are hard to debug. Python avoided it for decades by making = a statement only. The walrus operator was their compromise to allow convenient initialization while trying to prevent that bug class.

Today, Python’s walrus operator is accepted as a niche feature. It is used sparingly by many developers, mainly in specific cases, but it never became a commonly used or beloved part of the language.

A Better Solution for Mojo: Go-Inspired Assignment

I propose that Mojo makes := the standard operator for declaration + initialization, similar to Go:

# Declaration + initialization (preferred)
name := input("Name or 'quit': ")
count := len(data)
result := some_complex_function()

# Reassignment only
count = count + 1
name = "new value"

# Clean control flow
if name := input("Name: "); name != "quit":
    ...

Why This Would Be Excellent for Mojo

  • Prevents the dangerous class of logical bugs (if x = 5 instead of x == 5 becomes impossible or very obvious)
  • High internal consistency (no special walrus-only operator)
  • Excellent ergonomics (much less verbose than var + =)
  • Still feels familiar to Python developers
  • Aligns well with Mojo’s goals as a high-performance, statically typed language

Would the Mojo team and community consider making := the recommended/default way to declare new variables?

I’d especially love to hear from people who have used both Python and Go in larger projects.

Thanks for reading!

Follow-up:

One additional point I want to emphasize:
At the moment, variable declared with the keyword ‘var’ have block scope, whereas variables declared without “var”, i.e. with =, have function scope. This is inconsistent.

I believe all variables in Mojo should use block scoping (instead of Python’s function scoping).

For example, in this construct:

if name := input("Name: "); name != "quit":
    ...

the variable name should only be visible inside the if statement — not leak into the surrounding function scope.

Block scoping is preferable to function-wide scoping because it:

  • Prevents namespace pollution
  • Reduces accidental variable reuse bugs

The advantage may not be very large, but if you have a choice, then you should chose the better.

This combination (:= + block scoping) would give Mojo a very clean and modern variable declaration model.

What do you think?

I like the idea of having only explicit block scoped variable declarations. See discussion here: https://forum.modular.com/t/block-scope-vs-function-scope-of-variables

But I think var is already well established for this in Mojo. var is not only used for local variable declaration statements but as

  • an argument convention,
  • an iteration convention,
  • an instance variable declaration,
  • a closure convention

too.

Therefore I would rather require explicit var declarations than introduce the walrus operator for variable declaration statements. var already implies block scoping.

Dummy example to show off some usages of var:

@fieldwise_init
struct Foo:
    var value: Int

def print_doubled(var list: List[Int]):
    var text = "doubled: "
    for var value in list:
        value += value
        list.append(value)
    text += ",".join(list)
    print(text)


def main()
    print_doubled([1, 2, 3]) # doubled: 1,2,3,2,4,6

In all usages var has the same meaning: "a locally declared owned value binding“.

for var value in list:

O.K. so you want to drop the walrus operator completely from Mojo? How do you want to declare a variable in an expression like so?

if (length := len(some_list)) > 10:

The walrus operator is meant for expression assignment (like in Python). I would keep it that way in Mojo (it is already implemented that way).

You can prepend it with var to have the variable block scoped:

if (var length := len(some_list)) > 10:

This is approximately the same as:

var length = len(some_list)
if length > 10:

I have no issue with using var for all variable declarations — I actually think it makes more sense than the current approach. However, I’m not a fan of the walrus operator (:=) in this context. :joy:

Introducing a keyword that’s only useful in a narrow niche feels like unnecessary complexity. The likely result is the same as with Python: the walrus operator will see very limited adoption in the Mojo community because it disrupts established coding habits.

Compare these:

Current proposal:

if (var length := len(some_list)) > 10:

Simple & readable:

var length = len(some_list)
if length > 10:

I believe it would be cleaner to keep the declaration as a statement while still allowing it inside the if condition. You could achieve this by separating the declaration and the condition with a semicolon:

if var length = len(some_list); length > 10:

This keeps the language simpler, avoids a controversial operator, and still gives the convenience of declaring the variable close to its use.


But to be frank, I would probably use the simple & readable solution anyway. The additional variable in the function’s namespace is nothing to really worry about. You could drop this feature completely if you ask me.

Hi Kilian,

Thank you for starting a thread about this. It’s an interesting concept and always good to learn from other languages.

In Mojo however, we intentionally stay close to Python to make it easier to learn (and many other reasons). The cases we diverge (e.g. requiring static types) are related to the core mission and use-cases we need to support.

The assignment and walrus operators are already defined in Python, and Mojo follows their behavior. I don’t expect we will diverge here.

-Chris

Hi Chris,
thanks for taking the time to respond to my post. I appreciate the clear explanation and understand the direction.

Kilian

Hi Chris,

I fully understand and respect Mojo’s design philosophy of staying close to Python unless the language’s goals require a deliberate divergence.

That said, I’ve been wondering about the rationale behind the var keyword.

Python already offers a very natural syntax for typed variables:

x: Int = 42

An uninitialized declaration could be written as:

y: Int

For type inference, Python’s walrus operator (:=) already provides a concise way to introduce and initialize a variable, however merely in expressions. Using this keyword appears to be closer to python than the var keyword:

z := 42

Together this forms a clean, consistent system:

  • : introduces a type
  • = performs assignment
  • := performs type inference and assignment

No extra keyword appears to be necessary.

So my question is: What specific requirement does var fulfill that justifies diverging from Python’s existing patterns? I understand the motivation for static types, but the need for var is less clear to me.

I’d really appreciate hearing the thinking behind this design decision. Thanks!

Kilian

The walrus operator (:=) in Python is just an assignment operator for expressions like = is an assignment operator in statements. You can use a previously introduced variable in assignment expressions.

"The walrus operator (:=) in Python is an assignment expression — it performs assignment inside expressions, while = is the regular assignment statement. I said nothing else!

= handles both initial assignment and reassignment in python. Using := for cases where you want to distinguish declaration/initialization from simple reassignment (as Mojo might need) is a clean, Pythonic choice.

Additionally, using := for both statements and expressions would make declaration and assignment consistent, resulting in cleaner syntax overall. This truly kills two birds with one stone.

Oh, not just two birds, three birds, because you can drop the new keyword var, which deviates from python’s practices.

you can drop the new keyword var

One cannot drop var. We also support var a, b, ref c = ... in Mojo.

:= is used whenever you want to infer the type and assign a value.

The rational is that : stands for type and = stands for assign, thus infer type + assign :=

var c = is replaced by c :=
var a, b = is replaced by a, b :=

Simpler, cleaner and much closer to the original python syntax. There is no need for the var keyword, which is completely absent from Python.

This would imply, that the walrus operator (:=) can‘t be used anymore to re-assign an already declared variable like it is the case in Python and Mojo at the moment. Right?

BTW: var would still be needed in many places like descrbed in Proposal: Make ':=' the standard declaration operator in Mojo (Go-style) - #3 by christoph_schlumpf

It might be more consistent to always use var than having a different syntax here.

No, if you want to create a new variable x and assign a value form another variable y to it, you chose:

x := y

If the want to reassign the value of y to x, say x has been declared previously, then you chose:

x = y.

If you want to declare a variable without assigning a value to it, then you use:

x: Int

This form of declaration is already part of mojo’s syntax! I have not invented anything here.

So no, you do not need var for declaring a variable.

I am not talking about the ownership model, which does not exist in python. So the ownership model necessitates a deviation from python syntax under Chris’ design philosophy. Now I do not know whether var makes sense for taking ownership.

var: The function takes ownership of a value.

own makes more sense to me. But, this is beyond the scope of my proposal.

I don’t see how var (or really any keyword signaling the binding form) can be replaced at all. Ref and var are two different binding form.

I am not talking about ref at all. I am merely talking about var for declaring a variable. I think that should be quite clear for everyone now.

Even in the current form, you do not need var for declaring a variable: