Lambda Syntax in Mojo: A Problem That Doesn't Need to Exist

The official roadmap lists lambdas as pending, with the blocker being a syntax decision regarding type annotations.

I believe this is overthinking it. Lambdas don’t need inline type annotations because their types are already known from context.

Case 1: Lambdas as arguments (90% of use cases)

mojo

# The type of 'x' comes from the list itself
my_list.sort(key=lambda x: x.age)

# The type of 'i' comes from the range or vector context
parallel_for(lambda i: kernel(i), num_tasks)

# The type of 'event' comes from the API signature
button.on_click(lambda event: print(event.x))

In all these cases, the context tells the compiler exactly what the parameter type is. Explicit syntax like lambda x: Int -> ... would just be noisy and redundant.

Case 2: Lambdas stored in variables (context missing)
If there is no context to infer the type, we simply disallow the lambda. The compiler throws an error:

mojo

var double = lambda x: x * 2  # Error: cannot infer type of 'x'

The solution is to force the user to use a named function (def) with explicit annotations:

mojo

def double(x: Int) -> Int:
    return x * 2

If they insist on storing it in a variable, they can annotate the variable itself, not the lambda:

mojo

var double: def(Int) -> Int = lambda x: x * 2  # Valid: the variable provides context

Simple rule:

If context infers the type → lambda allowed. If not → compile error.

This removes any ambiguity and avoids having to invent awkward syntax just to annotate lambdas inline. This is what languages like Rust and Swift already do: contextual inference is sufficient; if context is missing, the compiler asks you to be explicit in another way.

Conclusion:
We don’t need to invent Scala-style syntax (x: Int => x + 1) or force inline annotations. Mojo already has type inference. We just need to apply it consistently:

  • With context → lambda.

  • Without context → error → use def or annotate the variable.

This solves the “syntax blocker” without adding an ounce of complexity to the language. Let’s stop over-engineering this and ship it. What do you all think?

@Sarctiann :waving_hand:

Contextual type inference is something we want (and will likely eventually support) for lambdas :smile:. However, lambdas are not a complete feature in Mojo: the first implementation only landed in the compiler less than a week ago.

The current syntax and behavior are a MVP, not the final design. There are still several aspects that need to be implemented and worked through.
So this is less a matter of the team over-engineering a finished feature and more a matter of the feature simply being at a very early stage of development.

What I’m trying to say is that “a function that’s given a type but not a name” simply seems wrong to me.

lambda functions should NOT be typed, and their use should be restricted to scenarios where the type can be inferred.

And as an extreme case, when a lambda is assigned to a variable, the variable can be signed… there’s absolutely no need to have anonymous typed functions.

In fact, I think the compiler could be generous enough to suggest moving a lambda assigned to a variable into a function definition.