Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/nightly' into move-strref-find…
Browse files Browse the repository at this point in the history
…-impl-to-span
  • Loading branch information
martinvuyk committed Dec 19, 2024
2 parents ef863cf + f3432eb commit 7b43af6
Show file tree
Hide file tree
Showing 86 changed files with 11,188 additions and 9,721 deletions.
782 changes: 782 additions & 0 deletions docs/changelog-released.md

Large diffs are not rendered by default.

692 changes: 54 additions & 638 deletions docs/changelog.md

Large diffs are not rendered by default.

34 changes: 16 additions & 18 deletions docs/manual/basics.mdx
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
---
title: Introduction to Mojo
title: Mojo language basics
sidebar_position: 1
sidebar_label: Overview
description: Introduction to Mojo's basic language features.
---

At this point, you should have already set up the Mojo
SDK and run ["Hello
world"](/mojo/manual/get-started). Now let's talk about how
to write Mojo code.
At this point, you should have already installed [Magic](/magic) to manage the
virtual environment and packages for your MAX and Mojo development (or
alternatively added the `max` package to a [conda](/magic/conda) development
environment). It's also a good idea to go through the [Get Started with
Mojo](/mojo/manual/get-started) tutorial to get a taste of what Mojo programming
is like. Now let's talk about how to write Mojo code.

If
you know Python, then a lot of Mojo code will look familiar. However, Mojo
is—first and foremost—designed for high-performance systems programming, with
features like strong type checking, memory safety, next-generation compiler
technologies, and more. As such, Mojo also has a lot in common with languages
like C++ and Rust.

Yet, we've designed Mojo to be flexible, so you can incrementally adopt
systems-programming features like strong type checking as you see fit—Mojo does
not *require* strong type checking.
If you know Python, then a lot of Mojo code will look familiar. However, Mojo
incorporates features like strong type checking, memory safety, next-generation
compiler technologies, and more. As such, Mojo also has a lot in common with
languages like C++ and Rust.

On this page, we'll introduce the essential Mojo syntax, so you can start
coding quickly and understand other Mojo code you encounter. Subsequent
Expand Down Expand Up @@ -181,8 +178,9 @@ each characteristic (such as each method). Each characteristic in a trait is a
"requirement" for the struct, and when your struct implements each requirement,
it's said to "conform" to the trait.

Currently, the only characteristics that traits can define are method signatures. Also, traits
currently cannot implement default behaviors for methods.
Currently, the only characteristics that traits can define are method
signatures. Also, traits currently cannot implement default behaviors for
methods.

Using traits allows you to write generic functions that can accept any type
that conforms to a trait, rather than accept only specific types.
Expand Down Expand Up @@ -355,7 +353,7 @@ from docstrings using the [`mojo doc` command](/mojo/cli/doc).

## Python integration

Mojo does not yet adopt the full syntax of Python, but we've built a mechanism to import
Mojo supports the ability to import
Python modules as-is, so you can leverage existing Python code right away.

For example, here's how you can import and use NumPy (you must have Python
Expand Down
40 changes: 40 additions & 0 deletions docs/manual/decorators/implicit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: '@implicit'
description: Marks a constructor as eligible for implicit conversion.
codeTitle: true

---

You can add the `@implicit` decorator on any single-argument constructor to
identify it as eligible for implicit conversion.

For example:

```mojo
struct MyInt:
var value: Int
@implicit
fn __init__(out self, value: Int):
self.value = value
fn __init__(out self, value: Float64):
self.value = int(value)
```

This implicit conversion constructor allows you to pass an `Int` to a function
that takes a `MyInt` argument, or assign an `Int` to a variable of type `MyInt`.
However, the constructor that takes a `Float64` value is **not** an implicit
conversion constructor, so it must be invoked explicitly:

```mojo
fn func(n: MyInt):
print("MyInt value: ", n.value)
fn main():
func(Int(42)) # Implicit conversion from Int: OK
func(MyInt(Float64(4.2))) # Explicit conversion from Float64: OK
func(Float64(4.2)) # Error: can't convert Float64 to MyInt
```
1 change: 1 addition & 0 deletions docs/manual/decorators/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ listing:
contents:
- always-inline.md
- copy-capture.md
- implicit.md
- nonmaterializable.md
- parameter.md
- register-passable.md
Expand Down
4 changes: 2 additions & 2 deletions docs/manual/decorators/parameter.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ this will be included in the binary

## Parametric for statement

You can add the `@parameter` decorator to an `for` loop to create a loop that's
You can add the `@parameter` decorator to a `for` loop to create a loop that's
evaluated at compile time. The loop sequence and induction values must be
a valid parameter expressions (that is, an expressions that evaluate at compile
valid parameter expressions (that is, expressions that evaluate at compile
time).

This has the effect of "unrolling" the loop.
Expand Down
118 changes: 112 additions & 6 deletions docs/manual/functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 2
description: Introduction to Mojo `fn` and `def` functions.
---

As mentioned in [Language basics](/mojo/manual/basics), Mojo supports two
As mentioned in the [syntax overview](/mojo/manual/basics), Mojo supports two
types of functions: `def` and `fn` functions. You can use either declaration
with any function, including the `main()` function, but they have different
default behaviors, as described on this page.
Expand Down Expand Up @@ -552,14 +552,14 @@ Thus, you can also pass a `StringLiteral` to a function that expects a `String`.
When resolving an overloaded function call, the Mojo compiler tries each
candidate function and uses the one that works (if only one version works), or
it picks the closest match (if it can determine a close match), or it reports
that the call is ambiguous (if it cant figure out which one to pick).
that the call is ambiguous (if it can't figure out which one to pick).

If the compiler can't figure out which function to use, you can resolve the
ambiguity by explicitly casting your value to a supported argument type. For
example, in the following code, we want to call the overloaded `foo()`
function, but both implementations accept an argument that supports [implicit
conversion](/mojo/manual/variables#implicit-type-conversion) from
`StringLiteral`. So, the call to `foo(string)` is ambiguous and creates a
example, in the following code, we want to call the overloaded `foo()` function,
but both implementations accept an argument that supports [implicit
conversion](/mojo/manual/lifecycle/life#constructors-and-implicit-conversion)
from `StringLiteral`. So, the call to `foo(string)` is ambiguous and creates a
compiler error. We can fix it by casting the value to the type we really want:

```mojo
Expand Down Expand Up @@ -596,3 +596,109 @@ different from function arguments, and used for compile-time metaprogramming),
you can also overload functions based on parameter types.

:::

## Return values

Return value types are declared in the signature using the
<code><strong>-></strong> <var>type</var></code> syntax. Values are
passed using the `return` keyword, which ends the function and returns the
identified value (if any) to the caller.

```mojo
def get_greeting() -> String:
return "Hello"
```

By default, the value is returned to the caller as an owned value. As with
arguments, a return value may be [implicitly
converted](/mojo/manual/lifecycle/life#constructors-and-implicit-conversion) to
the named return type. For example, the previous example calls `return` with a
string literal, `"Hello"`, which is implicitly converted to a `String`.

:::note Returning a reference

A function can also return a mutable or immutable reference using a `ref` return
value. For details, see
[Lifetimes, origins, and references](/mojo/manual/values/lifetimes).

:::

### Named results

Named function results allow a function to return a value that can't be moved or
copied. Named result syntax lets you specify a named, uninitialized variable to
return to the caller using the `out` argument convention:

```mojo
def get_name_tag(owned name: String, out name_tag: NameTag):
name_tag = NameTag(name^)
```

The `out` argument convention identifies an uninitialized variable that the
function must initialize. (This is the same as the `out` convention used in
[struct constructors](/mojo/manual/lifecycle/life#constructor).) A function can
have only one `out` argument. The `out` argument for a named result can appear
anywhere in the argument list, but by convention, it should be the last argument
in the list.

A function with a named result argument doesn't need to include an explicit
`return` statement, as shown above. If the function terminates without a `return`,
or at a `return` statement with no value, the value of the `out` argument is
returned to the caller. If it includes a `return` statement with a value, that
value is returned to the caller, as usual.

The fact that a function uses a named result is transparent to the caller. That
is, these two signatures are interchangeable to the caller:

```mojo
def get_name_tag(owned name: String) -> NameTag:
...
def get_name_tag(owned name: String, out name_tag: NameTag):
...
```

In both cases, the call looks like this:

```mojo
tag = get_name_tag("Judith")
```

Because the return value is assigned to this special `out` variable, it doesn't
need to be moved or copied when it's returned to the caller. This means that you
can create a function that returns a type that can't be moved or copied, and
which takes several steps to initialize:

```mojo
struct ImmovableObject:
var name: String
fn __init__(out self, owned name: String):
self.name = name^
def create_immovable_object(owned name: String, out obj: ImmovableObject):
obj = ImmovableObject(name^)
obj.name += "!"
# obj is implicitly returned
def main():
my_obj = create_immutable_object("Blob")
```

By contrast, the following function with a standard return value doesn't work:

```mojo
def create_immovable_object2(owned name: String) -> ImmovableObject:
obj = ImmovableObject(name^)
obj.name += "!"
return obj^ # Error: ImmovableObject is not copyable or movable
```

Because `create_immovable_object2` uses a local variable to store the object
while it's under construction, the return call requires it to be either moved
or copied to the callee. This isn't an issue if the newly-created value is
returned immediately:

```mojo
def create_immovable_object3(owned name: String) -> ImmovableObject:
return ImmovableObject(name^) # OK
```
Loading

0 comments on commit 7b43af6

Please sign in to comment.