-
Notifications
You must be signed in to change notification settings - Fork 0
/
documents.json
412 lines (412 loc) · 292 KB
/
documents.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
[
{
"section": "Language Basics",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Mojo Basics",
"description": "This contains the basics and introductory information about Mojo.",
"page_count": 1
},
"content": "Introduction to Mojo\n\nAt this point, you should have already set up the Mojo SDK and run \"Hello world\". Now let's talk about how to write Mojo code.\n\nYou probably already know that Mojo is designed as a superset of Python. So 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.\n\nYet, 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.\n\nOn this page, we'll introduce the essential Mojo syntax, so you can start coding quickly and understand other Mojo code you encounter. Subsequent sections in the Mojo Manual dive deeper into these topics, and links are provided below as appropriate.\n\nLet's get started! 🔥\n\nMojo is a young language and there are many features still missing. As such, Mojo is currently not meant for beginners. Even this basics section assumes some programming experience. However, throughout the Mojo Manual, we try not to assume experience with any particular language.\n\nFunctions\n\nMojo functions can be declared with either fn or def.\n\nThe fn declaration enforces type-checking and memory-safe behaviors (Rust style), while def allows no type declarations and dynamic behaviors (Python style).\n\nFor example, this def function doesn't require declaration of argument types or the return type:\n\n```def greet(name):\n return \"Hello, \" + name + \"!\"\n```\n\nWhile the same thing as an fn function requires that you specify the argument type and the return type like this:\n\n```fn greet2(name: String) -> String:\n return \"Hello, \" + name + \"!\"\n```\n\nBoth functions have the same result, but the fn function provides compile-time checks to ensure the function receives and returns the correct types. Whereas, the def function might fail at runtime if it receives the wrong type.\n\nCurrently, Mojo doesn't support top-level code in a .mojo (or .🔥) file, so every program must include a function named main() as the entry point. You can declare it with either def or fn:\n\n```def main():\n print(\"Hello, world!\")\n```\n\nYou don't need a main() function when coding in the REPL or in a Jupyter notebook.\n\nFor more details, see the page about functions.\n\nValue ownership and argument mutability\n\nIf you're wondering whether function arguments are passed by value or passed by reference, the short answer is: def functions receive arguments \"by value\" and fn functions receive arguments \"by immutable reference.\"\n\nThe longer short answer is that Mojo allows you to specify for each argument whether it should be passed by value (as owned), or whether it should be passed by reference (as borrowed for an immutable reference, or as inout for a mutable reference).\n\nThis feature is entwined with Mojo's value ownership model, which protects you from memory errors by ensuring that only one variable \"owns\" a value at any given time (but allowing other variables to receive a reference to it). Ownership then ensures that the value is destroyed when the lifetime of the owner ends (and there are no outstanding references).\n\nBut that's still a short answer, because going much further is a slippery slope into complexity that is out of scope for this section. For the complete answer, see the section about value ownership.\n\nVariables\n\nYou can declare variables with the var keyword. Or, if your code is in a def function, you can omit the var (in an fn function, you must include the var keyword).\n\nFor example:\n\n```def do_math(x):\n var y = x + x\n y = y * y\n print(y)\n```\n\nOptionally, you can also declare a variable type like this:\n\n```def add_one(x):\n var y: Int = 1\n print(x + y)\n```\n\nEven in an fn function, declaring the variable type is optional (only the argument and return types must be declared in fn functions).\n\nFor more details, see the page about variables.\n\nStructs\n\nYou can build high-level abstractions for types (or \"objects\") as a struct.\n\nA struct in Mojo is similar to a class in Python: they both support methods, fields, operator overloading, decorators for metaprogramming, and so on. However, Mojo structs are completely static—they are bound at compile-time, so they do not allow dynamic dispatch or any runtime changes to the structure. (Mojo will also support Python-style classes in the future.)\n\nFor example, here's a basic struct:\n\n```struct MyPair:\n var first: Int\n var second: Int\n\n fn __init__(inout self, first: Int, second: Int):\n self.first = first\n self.second = second\n\n fn dump(self):\n print(self.first, self.second)\n```\n\nAnd here's how you can use it:\n\n```fn use_mypair():\n var mine = MyPair(2, 4)\n mine.dump()\n```\n\nFor more details, see the page about structs.\n\nTraits\n\nA trait is like a template of characteristics for a struct. If you want to create a struct with the characteristics defined in a trait, you must implement 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.\n\nCurrently, the only characteristics that traits can define are method signatures. Also, traits currently cannot implement default behaviors for methods.\n\nUsing traits allows you to write generic functions that can accept any type that conforms to a trait, rather than accept only specific types.\n\nFor example, here's how you can create a trait (notice the function is not implemented):\n\n```trait SomeTrait:\n fn required_method(self, x: Int): ...\n```\n\nAnd here's how to create a struct that conforms to the trait:\n\n```@value\n struct SomeStruct(SomeTrait):\n fn required_method(self, x: Int):\n print(\"hello traits\", x)\n```\n\nThen, here's a function that uses the trait as an argument type (instead of the struct type):\n\n```fn fun_with_traits[T: SomeTrait](x: T):\n x.required_method(42)\n```\n\n```fn use_trait_function():\n var thing = SomeStruct()\n fun_with_traits(thing)\n```\n\nYou're probably wondering about the square brackets on fun_with_traits(). These aren't function arguments (which go in parentheses); these are function parameters, which we'll explain next.\n\nWithout traits, the x argument in fun_with_traits() would have to declare a specific type that implements required_method(), such as SomeStruct (but then the function would accept only that type). With traits, the function can accept any type for x as long as it conforms to (it \"implements\") SomeTrait. Thus, fun_with_traits() is known as a \"generic function\" because it accepts a generalized type instead of a specific type.\n\nFor more details, see the page about traits.\n\nParameterization\n\nIn Mojo, a parameter is a compile-time variable that becomes a runtime constant, and it's declared in square brackets on a function or struct. Parameters allow for compile-time metaprogramming, which means you can generate or modify code at compile time.\n\nMany other languages use \"parameter\" and \"argument\" interchangeably, so be aware that when we say things like \"parameter\" and \"parametric function,\" we're talking about these compile-time parameters. Whereas, a function \"argument\" is a runtime value that's declared in parentheses.\n\nParameterization is a complex topic that's covered in much more detail in the Metaprogramming section, but we want to break the ice just a little bit here. To get you started, let's look at a parametric function:\n\n```fn repeat[count: Int](msg: String):\n for i in range(count):\n print(msg)\n```\n\nThis function has one parameter of type Int and one argument of type String. To call the function, you need to specify both the parameter and the argument:\n\n```fn call_repeat():\n repeat[3](\"Hello\")\n # Prints \"Hello\" 3 times\n```\n\nBy specifying count as a parameter, the Mojo compiler is able to optimize the function because this value is guaranteed to not change at runtime. The compiler effectively generates a unique version of the repeat() function that repeats the message only 3 times. This makes the code more performant because there's less to compute at runtime.\n\nSimilarly, you can define a struct with parameters, which effectively allows you to define variants of that type at compile-time, depending on the parameter values.\n\nFor more detail on parameters, see the section on Metaprogramming.\n\nBlocks and statements\n\nCode blocks such as functions, conditions, and loops are defined with a colon followed by indented lines. For example:\n\n```def loop():\n for x in range(5):\n if x % 2 == 0:\n print(x)\n```\n\nYou can use any number of spaces or tabs for your indentation (we prefer 4 spaces).\n\nAll code statements in Mojo end with a newline. However, statements can span multiple lines if you indent the following lines. For example, this long string spans two lines:\n\n```def print_line():\n long_text = \"This is a long line of text that is a lot easier to read if\"\n \" it is broken up across two lines instead of one long line.\"\n print(long_text)\n```\n\nAnd you can chain function calls across lines:\n\n```def print_hello():\n text = String(\",\")\n .join(\"Hello\", \" world!\")\n print(text)\n```\n\nCode comments\n\nYou can create a one-line comment using the hash # symbol:\n\n```# This is a comment. The Mojo compiler ignores this line.\n```\n\nComments may also follow some code:\n\n```var message = \"Hello, World!\" # This is also a valid comment\n```\n\nYou can instead write longer comments across many lines using triple quotes:\n\n```\"\"\"\n This is also a comment, but it's easier to write across\n many lines, because each line doesn't need the # symbol.\n\"\"\"\n\nTriple quotes is the preferred method of writing API documentation. For example:\n\n```fn print(x: String):\n \"\"\"Prints a string.\n\n Args:\n x: The string to print.\n\"\"\"\n```\n\nDocumenting your code with these kinds of comments (known as \"docstrings\") is a topic we've yet to fully specify, but you can generate an API reference from docstrings using the mojo doc command.\n\nPython integration\n\nMojo is not yet a full superset of Python, but we've built a mechanism to import Python modules as-is, so you can leverage existing Python code right away.\n\nFor example, here's how you can import and use NumPy (you must have Python numpy installed):\n\n```from python import Python\n\nfn use_numpy() raises:\n var np = Python.import_module(\"numpy\")\n var ar = np.arange(15).reshape(3, 5)\n print(ar)\n print(ar.shape)\n```\n\nYou must have the Python module (such as numpy) installed already.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/basics",
"description": "Getting Started with Mojo"
}
]
},
{
"document_id": "2",
"metadata": {
"title": "Mojo Functions",
"description": "Learning about Mojo functions and how they are used.",
"page_count": 1
},
"content": "Functions\n\nAs mentioned in Language 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.\n\nWe believe both def and fn have good use cases and don't consider either to be better than the other. Deciding which to use is a matter of personal taste as to which style best fits a given task.\n\nWe believe Mojo's flexibility in this regard is a superpower that allows you to write code in the manner that's best for your project.\n\nFunctions declared inside a struct are called \"methods,\" but they have all the same qualities as \"functions\" described here.\n\nfn functions\n\nThe fn function has somewhat stricter rules than the def function.\n\nHere's an example of an fn function:\n\nfn greet(name: String) -> String:\n var greeting = \"Hello, \" + name + \"!\"\n return greeting\n\nAs far as a function caller is concerned, def and fn functions are interchangeable. That is, there's nothing a def can do that an fn can't (and vice versa). The difference is that, compared to a def function, an fn function is more strict on the inside.\n\nHere's everything to know about fn:\n\nArguments must specify a type (except for the self argument in struct methods).\n\nReturn values must specify a type, unless the function doesn't return a value.\n\nIf you don't specify a return type, it defaults to None (meaning no return value).\n\nBy default, arguments are received as an immutable reference (values are read-only, using the borrowed argument convention).\n\nThis prevents accidental mutations, and permits the use of non-copyable types as arguments.\n\nIf you want a local copy, you can simply assign the value to a local variable. Or, you can get a mutable reference to the value by declaring the inout argument convention).\n\nIf the function raises an exception, it must be explicitly declared with the raises keyword. (A def function does not need to declare exceptions.)\n\nBy enforcing these type checks, using the fn function helps avoid a variety of runtime errors.\n\ndef functions\n\nCompared to an fn function, a def function has fewer restrictions. The def function works more like a Python def function. For example, this function works the same in Python and Mojo:\n\ndef greet(name):\n greeting = \"Hello, \" + name + \"!\"\n return greeting\n\nIn a Mojo def function, you have the option to specify the argument type and the return type. You can also declare variables with var, with or without explicit typing. So you can write a def function that looks almost exactly like the fn function shown earlier:\n\ndef greet(name: String) -> String:\n var greeting = \"Hello, \" + name + \"!\"\n return greeting\n\nThis way, the compiler ensures that name is a string, and the return type is a string.\n\nHere's everything to know about def:\n\nArguments don't require a declared type.\n\nUndeclared arguments are actually passed as an object, which allows the function to receive any type (Mojo infers the type at runtime).\n\nReturn types don't need to be declared, and also default to object. (If a def function doesn't declare a return type of None, it's considered to return an object by default.)\n\nArguments are mutable. Arguments default to using the borrowed argument convention) like an fn function, with a special addition: if the function mutates the argument, it makes a mutable copy.\n\nIf an argument is an object type, it's received as a reference, following object reference semantics.\n\nIf an argument is any other declared type, it's received as a value.\n\nThe object type\n\nIf you don't declare the type for an argument or return value in a def, it becomes an object, which is unlike any other type in the standard library.\n\nThe object type allows for dynamic typing because it can actually represent any type in the Mojo standard library, and the actual type is inferred at runtime. (Actually, there's still more to do before it can represent all Mojo types.) This is great for compatibility with Python and all of the flexibility that it provides with dynamic types. However, this lack of type enforcement can lead to runtime errors when a function receives or returns an unexpected type.\n\nFor compatibility with Python, object values are passed using object reference semantics. As such, the object type is not compatible with the argument conventions that enforce value semantics. So, be careful if using object values alongside other strongly-typed values—their behavior might be inconsistent because object is the only type in the standard library that does not conform to full value semantics.\n\nTODO\n\nThe object type is still a work in progress. It doesn't support all of the possible underlying types, for example.\n\nFunction arguments\n\nAs noted in the previous sections, there are a few differences between how def and fn functions treat arguments. But most of the time they are the same.\n\nAs noted, there are some differences in argument conventions. Argument conventions are discussed in much more detail in the page on Ownership.\n\nThe other difference is that def functions don't need to specify an argument's type. If no type is specified, the argument is passed as an object.\n\nThe remaining rules for arguments described in this section apply to both def and fn functions.\n\nOptional arguments\n\nAn optional argument is one that includes a default value, such as the exp argument here:\n\nfn my_pow(base: Int, exp: Int = 2) -> Int:\n return base ** exp\n\nfn use_defaults():\n # Uses the default value for `exp`\n var z = my_pow(3)\n print(z)\n\nHowever, you cannot define a default value for an argument that's declared as inout.\n\nAny optional arguments must appear after any required arguments. Keyword-only arguments, discussed later, can also be either required or optional.\n\nKeyword arguments\n\nYou can also use keyword arguments when calling a function. Keyword arguments are specified using the format\n\nargument_name = argument_value\n\n. You can pass keyword arguments in any order:\n\nfn my_pow(base: Int, exp: Int = 2) -> Int:\n return base ** exp\n\nfn use_keywords():\n # Uses keyword argument names (with order reversed)\n var z = my_pow(exp=3, base=2)\n print(z)\n\nVariadic arguments\n\nVariadic arguments let a function accept a variable number of arguments. To define a function that takes a variadic argument, use the variadic argument syntax\n\n*argument_name\n\n:\n\nfn sum(*values: Int) -> Int:\n var sum: Int = 0\n for value in values:\n sum = sum + value\n return sum\n\nThe variadic argument values here is a placeholder that accepts any number of passed positional arguments.\n\nYou can define zero or more arguments before the variadic argument. When calling the function, any remaining positional arguments are assigned to the variadic argument, so any arguments declared after the variadic argument can only be specified by keyword (see Positional-only and keyword-only arguments).\n\nVariadic arguments can be divided into two categories:\n\nHomogeneous variadic arguments, where all of the passed arguments are the same type—all Int, or all String, for example.\n\nHeterogeneous variadic arguments, which can accept a set of different argument types.\n\nThe following sections describe how to work with homogeneous and heterogeneous variadic arguments.\n\nVariadic parameters\n\nMojo parameters are distinct from arguments (parameters are used for compile-time metaprogramming). Variadic parameters are supported, but with some limitations—for details see variadic parameters.\n\nHomogeneous variadic arguments\n\nWhen defining a homogeneous variadic argument, use\n\n*argument_name: argument_type\n\n:\n\ndef greet(*names: String):\n...\n\nInside the function body, the variadic argument is available as an iterable list for ease of use. Currently there are some differences in handling the list depending on whether the arguments are register-passable types (such as Int) or memory-only types (such as String). TODO: We hope to remove these differences in the future.\n\nRegister-passable types, such as Int, are available as a VariadicList type. As shown in the previous example, you can iterate over the values using a for..in loop.\n\nfn sum(*values: Int) -> Int:\n var sum: Int = 0\n for value in values:\n sum = sum+value\n return sum\n\nMemory-only types, such as String, are available as a VariadicListMem. Iterating over this list directly with a for..in loop currently produces a Reference for each value instead of the value itself. You must add an empty subscript operator [] to dereference the reference and retrieve the value:\n\ndef make_worldly(inout *strs: String):\n# Requires extra [] to dereference the reference for now.\n for i in strs:\n i[] += \" world\"\n\nAlternately, subscripting into a VariadicListMem returns the argument value, and doesn't require any dereferencing:\n\nfn make_worldly(inout *strs: String):\n # This \"just works\" as you'd expect!\n for i in range(len(strs)):\n strs[i] += \" world\"\n\nHeterogeneous variadic arguments\n\nImplementing heterogeneous variadic arguments is somewhat more complicated than homogeneous variadic arguments. Writing generic code to handle multiple argument types requires traits and parameters. So the syntax may look a little unfamiliar if you haven't worked with those features. The signature for a function with a heterogeneous variadic argument looks like this:\n\ndef count_many_things[*ArgTypes: Intable](*args: *ArgTypes):\n...\n\nThe parameter list, [*ArgTypes: Intable] specifies that the function takes an ArgTypes parameter, which is a list of types, all of which conform to the Intable trait. The argument list, (*args: *ArgTypes) has the familiar *args for the variadic argument, but instead of a single type, its type is defined as list of types, *ArgTypes.\n\nThis means that each argument in args has a corresponding type in ArgTypes, so args[n] is of type ArgTypes[n].\n\nInside the function, args is available as a VariadicPack. The easiest way to work with the arguments is to use the each() method to iterate through the VariadicPack:\n\nfn count_many_things[*ArgTypes: Intable](*args: *ArgTypes) -> Int:\n var total = 0\n\n @parameter\n fn add[Type: Intable](value: Type):\n total += int(value)\n\n args.each[add]()\n return total\n\nprint(count_many_things(5, 11.7, 12))\n\n28\n\nIn the example above, the add() function is called for each argument in turn, with the appropriate value and Type values. For instance, add() is first called with value=5 and Type=Int, then with value=11.7 and Type=Float64.\n\nAlso, note that when calling count_many_things(), you don't actually pass in a list of argument types. You only need to pass in the arguments, and Mojo generates the ArgTypes list itself.\n\nAs a small optimization, if your function is likely to be called with a single argument frequently, you can define your function with a single argument followed by a variadic argument. This lets the simple case bypass populating and iterating through the VariadicPack.\n\nFor example, given a print_string() function that prints a single string, you could re-implement the variadic print() function with code like this:\n\nfn print_string(s: String):\n print(s, end=\"\")\n\nfn print_many[T: Stringable, *Ts: Stringable](first: T, *rest: *Ts):\n print_string(str(first))\n\n @parameter\n fn print_elt[T: Stringable](a: T):\n print_string(\" \")\n print_string(str(a))\n rest.each[print_elt]()\n\nprint_many(\"Bob\")\n\nBob\n\nIf you call print_many() with a single argument, it calls print_string() directly. The VariadicPack is empty, so each() returns immediately without calling the print_elt() function.\n\nVariadic keyword arguments\n\nMojo functions also support variadic keyword arguments (**kwargs). Variadic keyword arguments allow the user to pass an arbitrary number of keyword arguments. To define a function that takes a variadic keyword argument, use the variadic keyword argument syntax\n\n**kw_argument_name\n\n:\n\nfn print_nicely(**kwargs: Int) raises:\n for key in kwargs.keys():\n print(key[], \"=\", kwargs[key[]])\n\n # prints:\n # `a = 7`\n # `y = 8`\nprint_nicely(a=7, y=8)\n\nIn this example, the argument name kwargs is a placeholder that accepts any number of keyword arguments. Inside the body of the function, you can access the arguments as a dictionary of keywords and argument values (specifically, an instance of OwnedKwargsDict).\n\nThere are currently a few limitations:\n\nVariadic keyword arguments are always implicitly treated as if they were declared with the owned argument convention, and can't be declared otherwise:\n\n# Not supported yet.\n fn borrowed_var_kwargs(borrowed **kwargs: Int): ...\n\nAll the variadic keyword arguments must have the same type, and this determines the type of the argument dictionary. For example, if the argument is **kwargs: Float64 then the argument dictionary will be a OwnedKwargsDict[Float64].\n\nThe argument type must conform to the CollectionElement trait. That is, the type must be both Movable and Copyable.\n\nDictionary unpacking is not supported yet:\n\nfn takes_dict(d: Dict[String, Int]):\n print_nicely(**d) # Not supported yet.\n\nVariadic keyword parameters are not supported yet:\n\n# Not supported yet.\n fn var_kwparams[**kwparams: Int](): ...\n\nPositional-only and keyword-only arguments\n\nWhen defining a function, you can restrict some arguments so that they can only be passed as positional arguments, or they can only be passed as keyword arguments.\n\nTo define positional-only arguments, add a slash character (/) to the argument list. Any arguments before the / are positional-only: they can't be passed as keyword arguments. For example:\n\nfn min(a: Int, b: Int, /) -> Int:\n return a if a < b else b\n\nThis min() function can be called with min(1, 2) but can't be called using keywords, like min(a=1, b=2).\n\nThere are several reasons you might want to write a function with positional-only arguments:\n\nThe argument names aren't meaningful for the the caller.\n\nYou want the freedom to change the argument names later on without breaking backward compatibility.\n\nFor example, in the min() function, the argument names don't add any real information, and there's no reason to specify arguments by keyword.\n\nFor more information on positional-only arguments, see PEP 570 – Python Positional-Only Parameters.\n\nKeyword-only arguments are the inverse of positional-only arguments: they can only be specified by keyword. If a function accepts variadic arguments, any arguments defined after the variadic arguments are treated as keyword-only. For example:\n\nfn sort(*values: Float64, ascending: Bool = True): ...\n\nIn this example, the user can pass any number of Float64 values, optionally followed by the keyword ascending argument:\n\nvar a = sort(1.1, 6.5, 4.3, ascending=False)\n\nIf the function doesn't accept variadic arguments, you can add a single star (*) to the argument list to separate the keyword-only arguments:\n\nfn kw_only_args(a1: Int, a2: Int, *, double: Bool) -> Int:\n var product = a1 * a2\n if double:\n return product * 2\n else:\n return product\n\nKeyword-only arguments often have default values, but this is not required. If a keyword-only argument doesn't have a default value, it is a required keyword-only argument. It must be specified, and it must be specified by keyword.\n\nAny required keyword-only arguments must appear in the signature before any optional keyword-only arguments. That is, arguments appear in the following sequence a function signature:\n\nRequired positional arguments.\n\nOptional positional arguments.\n\nVariadic arguments.\n\nRequired keyword-only arguments.\n\nOptional keyword-only arguments.\n\nVariadic keyword arguments.\n\nFor more information on keyword-only arguments, see PEP 3102 – Keyword-Only Arguments.\n\nOverloaded functions\n\nIf a def function does not specify argument types, then it can accept any data type and decide how to handle each type internally. This is nice when you want expressive APIs that just work by accepting arbitrary inputs, so there's usually no need to write function overloads for a def function.\n\nOn the other hand, all fn functions must specify argument types, so if you want a function to work with different data types, you need to implement separate versions of the function that each specify different argument types. This is called \"overloading\" a function.\n\nFor example, here's an overloaded add() function that can accept either Int or String types:\n\nfn add(x: Int, y: Int) -> Int:\n return x + y\n\nfn add(x: String, y: String) -> String:\n return x + y\n\nIf you pass anything other than Int or String to the add() function, you'll get a compiler error. That is, unless Int or String can implicitly cast the type into their own type. For example, String includes an overloaded version of its constructor (__init__()) that accepts a StringLiteral value. Thus, you can also pass a StringLiteral to a function that expects a String.\n\nWhen 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 can’t figure out which one to pick).\n\nIf 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 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:\n\n@value\n struct MyString:\n fn __init__(inout self, string: StringLiteral):\n pass\n\nfn foo(name: String):\n print(\"String\")\n\nfn foo(name: MyString):\n print(\"MyString\")\n\nfn call_foo():\n alias string: StringLiteral = \"Hello\"\n # foo(string) # This call is ambiguous because two `foo` functions match it\n foo(MyString(string))\n\nWhen resolving an overloaded function, Mojo does not consider the return type or other contextual information at the call site—only the argument types affect which function is selected.\n\nOverloading also works with combinations of both fn and def functions. For example, you could define multiple fn function overloads and then one or more def versions that don't specify all argument types, as a fallback.\n\nAlthough we haven't discussed parameters yet (they're different from function arguments, and used for compile-time metaprogramming), you can also overload functions based on parameter types.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/functions",
"description": "Learn about Mojo Functions"
}
]
},
{
"document_id": "3",
"metadata": {
"title": "Mojo Variables",
"description": "Learning about Mojo variables and how to properly use them.",
"page_count": 1
},
"content": "Variables\n\nA variable is a name that holds a value or object. All variables in Mojo are mutable—their value can be changed. (If you want to define a constant value that can't change at runtime, see the alias keyword.)\n\nMojo has two kinds of variables:\n\nExplicitly-declared variables are created with the var keyword, and may include type annotations.\n\n```var a = 5\nvar b: Float64 = 3.14```\n\nImplicitly-declared variables are created with an assignment statement:\n\n```a = 5\nb = 3.14```\n\nBoth types of variables are strongly-typed: the variable receives a type when it's created, and the type never changes. You can't assign a variable a value of a different type:\n\n```count = 8 # count is type Int\ncount = \"Nine?\" # Error: can't implicitly convert 'StringLiteral' to 'Int'```\n\nSome types support implicit conversions from other types. For example, an integer value can implicitly convert to a floating-point value:\n\n```var temperature: Float64 = 99\nprint(temperature)```\n\nImplicitly-declared variables\n\nYou can create a variable with just a name and a value. For example:\n\n```name = String(\"Sam\")\nuser_id = 0```\n\nImplicitly-declared variables are strongly typed: they take the type from the first value assigned to them. For example, the user_id variable above is type Int, while the name variable is type String. You can't assign a string to user_id or an integer to name.\n\nExplicitly-declared variables\n\nYou can declare a variable with the var keyword. For example:\n\n```var name = String(\"Sam\")\nvar user_id: Int```\n\nThe name variable is initialized to the string \"Sam\". The user_id variable is uninitialized, but it has a declared type, Int for an integer value.\n\nSince variables are strongly typed, you can't assign a variable a value of a different type, unless those types can be implicitly converted. For example, this code will not compile:\n\n```var user_id: Int = \"Sam\"```\n\nType annotations\n\nAlthough Mojo can infer a variable type from the first value assigned to a variable, it also supports static type annotations on variables. Type annotations provide a more explicit way of specifying the variable's type.\n\nTo specify the type for a variable, add a colon followed by the type name:\n\n```var name: String = get_name()```\n\nThis makes it clear that name is type String, without knowing what the get_name() function returns.\n\nLate initialization\n\nUsing type annotations allows for late initialization. For example, notice here that the z variable is first declared with just a type, and the value is assigned later:\n\n```fn my_function(x: Int):\n var z: Float32\n if x != 0:\n z = 1.0\n else:\n z = foo()\n print(z)```\n\nIf you try to pass an uninitialized variable to a function or use it on the right-hand side of an assignment statement, compilation fails.\n\n```var z: Float32\nvar y = z # Error: use of uninitialized value 'z'```\n\nImplicit type conversion\n\nSome types include built-in type conversion (type casting) from one type into its own type. For example, if you assign an integer to a variable that has a floating-point type, it converts the value instead of giving a compiler error:\n\n```var number: Float64 = 1```\n\nVariable scopes\n\nVariables declared with var are bound by lexical scoping. This means that nested code blocks can read and modify variables defined in an outer scope. But an outer scope cannot read variables defined in an inner scope at all.\n\nFor example:\n\n```def lexical_scopes():\n var num = 1\n var dig = 1\n if num == 1:\n print(\"num:\", num) # Reads the outer-scope 'num'\n var num = 2 # Creates new inner-scope 'num'\n print(\"num:\", num) # Reads the inner-scope 'num'\n dig = 2 # Updates the outer-scope 'dig'\n print(\"num:\", num) # Reads the outer-scope 'num'\n print(\"dig:\", dig) # Reads the outer-scope 'dig'```\n\nThis is in contrast to implicitly-declared variables (those without the var keyword), which use function-level scoping (consistent with Python variable behavior). That means, when you change the value of an implicitly-declared variable inside the if block, it actually changes the value for the entire function.\n\nFor example, here's the same code but without the var declarations:\n\n```def function_scopes():\n num = 1\n if num == 1:\n print(num) # Reads the function-scope 'num'\n num = 2 # Updates the function-scope variable\n print(num) # Reads the function-scope 'num'\n print(num) # Reads the function-scope 'num'```\n\n1\n2\n2\n\nNow, the last print() function sees the updated num value from the inner scope, because implicitly-declared variables (Python-style variables) use function-level scope (instead of lexical scope).",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/variables",
"description": "Learn about Mojo Variables"
}
]
},
{
"document_id": "4",
"metadata": {
"title": "Mojo Types",
"description": "Learning about Mojo Types and how to apply them appropriately.",
"page_count": 1
},
"content": "Types\n\nAll values in Mojo have an associated data type. Most of the types are nominal types, defined by a struct. These types are nominal (or 'named') because type equality is determined by the type's name, not its structure.\n\nThere are a some types that aren't defined as structs:\n\nFunctions are typed based on their signatures.\nNoneType is a type with one instance, the None object, which is used to signal 'no value.'\n\nMojo comes with a standard library that provides a number of useful types and utility functions. These standard types aren’t privileged. Each of the standard library types is defined just like user-defined types—even basic types like Int and String. But these standard library types are the building blocks you'll use for most Mojo programs.\n\nThe most common types are built-in types, which are always available and don't need to be imported. These include types for numeric values, strings, boolean values, and others.\n\nThe standard library also includes many more types that you can import as needed, including collection types, utilities for interacting with the filesystem and getting system information, and so on.\n\nNumeric types\n\nMojo's most basic numeric type is Int, which represents a signed integer of the largest size supported by the system—typically 64 bits or 32 bits.\n\nMojo also has built-in types for integer and floating-point values of various precisions:\n\nType name | Description\n--- | ---\nInt8 | 8-bit signed integer\nUInt8 | 8-bit unsigned integer\nInt16 | 16-bit signed integer\nUInt16 | 16-bit unsigned integer\nInt32 | 32-bit signed integer\nUInt32 | 32-bit unsigned integer\nInt64 | 64-bit signed integer\nUInt64 | 64-bit unsigned integer\nFloat16 | 16-bit floating point number (IEEE 754-2008 binary16)\nFloat32 | 32-bit floating point number (IEEE 754-2008 binary32)\nFloat64 | 64-bit floating point number (IEEE 754-2008 binary64)\n\nAll of the numeric types support the usual numeric and bitwise operators. The math module provides a number of additional math functions.\n\nYou may wonder when to use Int and when to use the other integer types. In general, Int is a good safe default when you need an integer type and you don't require a specific bit width.\n\nFloating-point numbers\n\nFloating-point types represent real numbers. Because not all real numbers can be expressed in a finite number of bits, floating-point numbers can't represent every value exactly.\n\nThe floating-point types listed in Table 1—Float64, Float32, and Float16—follow the IEEE 754-2008 standard for representing floating-point values. Each type includes a sign bit, one set of bits representing an exponent, and another set representing the fraction or mantissa.\n\nType name | Sign | Exponent | Mantissa\n--- | --- | --- | ---\nFloat64 | 1 bit | 11 bits | 52 bits\nFloat32 | 1 bit | 8 bits | 23 bits\nFloat16 | 1 bit | 5 bits | 10 bits\n\nA few things to note with floating-point values:\n\nRounding errors may produce unexpected results. For example, 1/3 can't be represented exactly in these floating-point formats. The more operations you perform with floating-point numbers, the more the rounding errors accumulate.\n\nSpace between consecutive numbers is variable across the range of a floating-point number format. For numbers close to zero, the distance between consecutive numbers is very small, while for large numbers, the space is greater than 1.\n\nBecause the values are approximate, it is rarely useful to compare them with the equality operator (==). Instead, use comparison operators or the math.isclose() function.\n\nNumeric literals\n\nIn addition to these numeric types, the standard libraries provide integer and floating-point literal types, IntLiteral and FloatLiteral. These are used at compile time to represent literal numbers that appear in the code.\n\nTable 3 summarizes the literal formats you can use to represent numbers.\n\nFormat | Examples | Notes\n--- | --- | ---\nInteger literal | 1760 | Integer literal in decimal format.\nHexadecimal literal | 0xaa, 0xFF | Hex digits are case-insensitive.\nOctal literal | 0o77 | Octal format.\nBinary literal | 0b0111 | Binary format.\nFloating-point literal | 3.14, 1.2e9 | Must include a decimal point.\n\nAt compile time, the literal types are arbitrary-precision values, allowing for compile-time calculations without overflow or rounding errors.\n\nAt runtime, they are converted to finite-precision types—Int for integers, Float64 for floating-point values.\n\nSIMD and DType\n\nTo support high-performance numeric processing, Mojo uses the SIMD type as the basis for its numeric types. SIMD (single instruction, multiple data) allows you to perform an operation on an entire set of operands at once.\n\nA SIMD value represents a SIMD vector—a fixed-size array of values that can fit into a processor's register. SIMD vectors are defined by two parameters: a DType value, defining the data type in the vector, and the number of elements, which must be a power of two.\n\nScalar values\n\nThe SIMD module defines several type aliases that are shorthand for different types of SIMD vectors. Scalar refers to a SIMD vector with a single element. The numeric types like Int8 and Float32 are actually type aliases for scalar values:\n\n```alias Scalar = SIMD[size=1]\nalias Int8 = Scalar[DType.int8]\nalias Float32 = Scalar[DType.float32]```\n\nStrings\n\nMojo's String type represents a mutable string. Strings support a variety of operators and methods. Most standard library types conform to the Stringable trait, which allows them to be converted to strings using the str() function.\n\n```var s = str('Items in list: ') + str(5)\nprint(s)```\n\nString literals\n\nString literals are enclosed in single or double quotes. Adjacent literals are concatenated together, and triple quotes are used for multi-line strings.\n\n```var s = '''Multi-line string'''```\n\nBooleans\n\nMojo's Bool type represents a boolean value, which can be True or False. The not operator negates a boolean.\n\n```var conditionA = False\nvar conditionB: Bool\nconditionB = not conditionA\nprint(conditionA, conditionB)```\n\nCollections\n\nMojo includes basic collection types like List, Dict, Set, and Optional. These are generic types, and you can specify the type at compile time. Lists are dynamically-sized arrays of elements, and Dict is an associative array of key-value pairs.\n\n```var l = List[Int](1, 2, 3, 4)\nvar d = Dict[String, Float64]()\n``` Optional represents a value that may or may not be present. You can retrieve its value using the value() method or the or_else() method.\n\n```var opt1 = Optional(5)\nprint(opt1.or_else('Hello'))```\n\nRegister-passable and memory-only types\n\nRegister-passable types are composed of fixed-size data types that can be stored in a machine register. Memory-only types consist of types that have pointers or references to dynamically allocated memory. Trivial types don't require custom logic in lifecycle methods.\n\nAnyType and AnyTrivialRegType\n\nAnyType represents any Mojo type, and AnyTrivialRegType represents any Mojo type that's register-passable. You'll see them in function signatures like this:\n\n```fn any_type_function[ValueType: AnyTrivialRegType](value: ValueType):``` \n\nThis means that the function `any_type_function` can take an argument `value` of type `ValueType`, where `ValueType` must be a register-passable type, determined at compile time. \n\nThese metatypes (AnyType and AnyTrivialRegType) act as types of types, allowing the function to accept any compatible Mojo type. While you might still encounter these types in some parts of the standard library, the codebase is gradually being migrated to a more generic approach that doesn't distinguish between register-passable and memory-only types. \n\nThe goal is to make the difference between register-passable and memory-only types transparent to the user, ensuring that APIs work seamlessly with both categories. Over time, trivial types will also be separated from the @register_passable decorator, creating a more unified experience for developers.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/types",
"description": "Learn about Mojo Types"
}
]
},
{
"document_id": "5",
"metadata": {
"title": "Mojo Control Flow",
"description": "How to use control flow precisely in Mojo.",
"page_count": 1
},
"content": "Control flow\n\nMojo includes several traditional control flow structures for conditional and repeated execution of code blocks.\n\nThe if statement\n\nMojo supports the if statement for conditional code execution. With it, you can conditionally execute an indented code block if a given boolean expression evaluates to True.\n\n```temp_celsius = 25\nif temp_celsius > 20:\n print('It is warm.')\n print('The temperature is', temp_celsius * 9 / 5 + 32, 'Fahrenheit.')```\n\nOptionally, an if statement can include any number of additional elif clauses and an else clause to handle multiple conditions.\n\n```temp_celsius = 25\nif temp_celsius <= 0:\n print('It is freezing.')\nelif temp_celsius < 20:\n print('It is cool.')\nelif temp_celsius < 30:\n print('It is warm.')\nelse:\n print('It is hot.')```\n\nShort-circuit evaluation\n\nMojo follows short-circuit evaluation semantics for boolean operators. If the first argument of an or operator evaluates to True, the second argument is not evaluated. The same applies to the and operator if the first argument evaluates to False.\n\n```def true_func() -> Bool:\n print('Executing true_func')\n return True\n\ndef false_func() -> Bool:\n print('Executing false_func')\n return False\n\nif true_func() or false_func():\n print('True result')```\n\nConditional expressions\n\nMojo also supports conditional expressions using the syntax:\n\n```result = true_value if condition else false_value```\n\nThis is a concise way to assign a value based on a boolean condition.\n\n```temp_celsius = 15\nforecast = 'warm' if temp_celsius > 20 else 'cool'\nprint('The forecast for today is', forecast)```\n\nThe while statement\n\nThe while loop repeatedly executes a code block while a given boolean expression evaluates to True.\n\n```fib_prev = 0\nfib_curr = 1\nwhile fib_curr < 50:\n print(fib_curr, end=', ')\n fib_prev, fib_curr = fib_curr, fib_prev + fib_curr```\n\nA continue statement skips the rest of the loop iteration, while a break statement terminates the loop entirely.\n\n```n = 0\nwhile n < 5:\n n += 1\n if n == 3:\n break\n print(n, end=', ')```\n\nThe for statement\n\nThe for loop iterates over a sequence, executing a code block for each element. Mojo for loops can iterate over any type that implements an `__iter__()` method.\n\n```from collections import List\nstates = List[String]('California', 'Hawaii', 'Oregon')\nfor state in states:\n print(state[])```\n\nMojo also supports iteration over sets and dictionaries.\n\n```from collections import Dict\ncapitals = Dict[String, String]()\ncapitals['California'] = 'Sacramento'\ncapitals['Hawaii'] = 'Honolulu'\nfor state in capitals:\n print(capitals[state[]], state[])```\n\nOptionally, for loops can include an else clause, which executes after iterating through all elements unless a break statement terminates the loop.\n\n```for i in range(5):\n print(i)\nelse:\n print('Loop completed')```\n\nPython collections\n\nMojo's for loop also supports iterating over Python collections. Each item retrieved by the loop is a PythonObject wrapper.\n\n```from python import Python\npy_list = Python.evaluate('[42, \"cat\", 3.14159]')\nfor py_obj in py_list:\n print(py_obj)```\n\nYou can iterate over Python dictionaries by iterating over keys or using the `items()` method to access key-value pairs.\n\n```py_dict = Python.evaluate('{\"a\": 1, \"b\": 2.71828, \"c\": \"sushi\"}')\nfor py_key in py_dict:\n print(py_key, py_dict[py_key])```\n\nAlternatively, you can use the `items()` method to get tuples of keys and values.\n\n```for py_tuple in py_dict.items():\n print(py_tuple[0], py_tuple[1])```\n\nThis method allows you to access both the key and value within each iteration of the loop, making it convenient for working with Python dictionaries.\n\n### TODO\nMojo's for loop currently assigns the loop index variable a Reference to each element when iterating over native Mojo collections, requiring the use of the dereference operator `[]` within the loop body. This behavior may change in future versions of Mojo.\n\nWhen iterating over Python collections, each element is assigned as a PythonObject wrapper, and dereferencing is not necessary.\n\nThere are two techniques for iterating over a Python dictionary:\n\n1. Iterating directly over the dictionary, which produces a sequence of keys:\n\n```from python import Python\npy_dict = Python.evaluate('{\"a\": 1, \"b\": 2.71828, \"c\": \"sushi\"}')\nfor py_key in py_dict:\n print(py_key, py_dict[py_key])```\n\n2. Using the `items()` method to iterate over key-value pairs:\n\n```for py_tuple in py_dict.items():\n print(py_tuple[0], py_tuple[1])``` \n\nBoth techniques provide flexibility when iterating over Python collections, depending on whether you need to work with keys alone or both keys and values in each iteration.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/control-flow",
"description": "Learn about Mojo Control Flow"
}
]
},
{
"document_id": "6",
"metadata": {
"title": "Mojo Structs",
"description": "How to use structs in Mojo.",
"page_count": 1
},
"content": "Structs\n\nA Mojo struct is a data structure that allows you to encapsulate fields and methods that operate on an abstraction, such as a data type or an object. Fields are variables that hold data relevant to the struct, and methods are functions inside a struct that generally act upon the field data.\n\nFor example, if you're building a graphics program, you can use a struct to define an Image that has fields to store information about each image (such as the pixels) and methods that perform actions on it (such as rotate it).\n\nFor the most part, Mojo's struct format is designed to provide a static, memory-safe data structure for high-level data types used in programs. For example, all the data types in Mojo's standard library (such as Int, Bool, String, and Tuple) are defined as structs.\n\nIf you understand how functions and variables work in Mojo, you probably noticed that Mojo is designed to provide dynamic programming features in a def function while enforcing stronger code safety in fn functions. When it comes to structs, Mojo leans toward the safe side: You can still choose whether to use either def or fn declarations for methods, but all fields must be declared with var.\n\nStruct definition\n\nYou can define a simple struct called MyPair with two fields like this:\n\nstruct MyPair:\n var first: Int\n var second: Int\n\nHowever, you can't instantiate this struct because it has no constructor method. So here it is with a constructor to initialize the two fields:\n\nstruct MyPair:\n var first: Int\n var second: Int\n\n fn __init__(inout self, first: Int, second: Int):\n self.first = first\n self.second = second\n\nNotice that the first argument in the __init__() method is inout self. For now, ignore inout (it's an argument convention that declares self as a mutable reference); all you need to know right now is that self must be the first argument. It references the current struct instance (it allows code in the method to refer to 'itself'). When you call the constructor, you never pass a value for self—Mojo passes it in automatically.\n\nThe __init__() method is one of many special methods (also known as 'dunder methods' because they have double underscores) with pre-determined names.\n\nYou can't assign values when you declare fields. You must initialize all of the struct's fields in the constructor. (If you try to leave a field uninitialized, the code won't compile.)\n\nOnce you have a constructor, you can create an instance of MyPair and set the fields:\n\nvar mine = MyPair(2,4)\nprint(mine.first)\n\n2\n\nMethods\n\nIn addition to special methods like __init__(), you can add any other method you want to your struct. For example:\n\nstruct MyPair:\n var first: Int\n var second: Int\n\n fn __init__(inout self, first: Int, second: Int):\n self.first = first\n self.second = second\n\n fn get_sum(self) -> Int:\n return self.first + self.second\n\nvar mine = MyPair(6, 8)\nprint(mine.get_sum())\n\n14\n\nNotice that get_sum() also uses the self argument, because this is the only way you can access the struct's fields in a method. The name self is just a convention, and you can use any name you want to refer to the struct instance that is always passed as the first argument.\n\nMethods that take the implicit self argument are called instance methods because they act on an instance of the struct.\n\nThe self argument in a struct method is the only argument in an fn function that does not require a type. You can include it if you want, but you can elide it because Mojo already knows its type (MyPair in this case).\n\nStatic methods\n\nA struct can also have static methods. A static method can be called without creating an instance of the struct. Unlike instance methods, a static method doesn't receive the implicit self argument, so it can't access any fields on the struct.\n\nTo declare a static method, use the @staticmethod decorator and don't include a self argument:\n\nstruct Logger:\n\n fn __init__(inout self):\n pass\n\n @staticmethod\n fn log_info(message: String):\n print('Info: ', message)\n\nYou can invoke a static method by calling it on the type (in this case, Logger). You can also call it on an instance of the type. Both forms are shown below:\n\nLogger.log_info('Static method called.')\nvar l = Logger()\nl.log_info('Static method called from instance.')\n\nInfo: Static method called.\nInfo: Static method called from instance.\n\nStructs compared to classes\n\nIf you're familiar with other object-oriented languages, then structs might sound a lot like classes, and there are some similarities, but also some important differences. Eventually, Mojo will also support classes to match the behavior of Python classes.\n\nSo, let's compare Mojo structs to Python classes. They both support methods, fields, operator overloading, decorators for metaprogramming, and more, but their key differences are as follows:\n\nPython classes are dynamic: they allow for dynamic dispatch, monkey-patching (or 'swizzling'), and dynamically binding instance fields at runtime.\n\nMojo structs are static: they are bound at compile-time (you cannot add methods at runtime). Structs allow you to trade flexibility for performance while being safe and easy to use.\n\nMojo structs do not support inheritance ('sub-classing'), but a struct can implement traits.\n\nPython classes support class attributes—values that are shared by all instances of the class, equivalent to class variables or static data members in other languages.\n\nMojo structs don't support static data members.\n\nSyntactically, the biggest difference compared to a Python class is that all fields in a struct must be explicitly declared with var.\n\nIn Mojo, the structure and contents of a struct are set at compile time and can’t be changed while the program is running. Unlike in Python, where you can add, remove, or change attributes of an object on the fly, Mojo doesn’t allow that for structs.\n\nHowever, the static nature of structs helps Mojo run your code faster. The program knows exactly where to find the struct’s information and how to use it without any extra steps or delays at runtime.\n\nMojo’s structs also work really well with features you might already know from Python, like operator overloading (which lets you change how math symbols like + and - work with your own data, using special methods).\n\nAs mentioned above, all Mojo's standard types (Int, String, etc.) are made using structs, rather than being hardwired into the language itself. This gives you more flexibility and control when writing your code, and it means you can define your own types with all the same capabilities (there's no special treatment for the standard library types).\n\nSpecial methods\n\nSpecial methods (or 'dunder methods') such as __init__() are pre-determined method names that you can define in a struct to perform a special task.\n\nAlthough it's possible to call special methods with their method names, the point is that you never should, because Mojo automatically invokes them in circumstances where they're needed (which is why they're also called 'magic methods'). For example, Mojo calls the __init__() method when you create an instance of the struct; and when Mojo destroys the instance, it calls the __del__() method (if it exists).\n\nEven operator behaviors that appear built-in (+, <, ==, |, and so on) are implemented as special methods that Mojo implicitly calls upon to perform operations or comparisons on the type that the operator is applied to.\n\nMojo supports a long list of special methods; far too many to discuss here, but they generally match all of Python's special methods and they usually accomplish one of two types of tasks:\n\nOperator overloading: A lot of special methods are designed to overload operators such as < (less-than), + (add), and | (or) so they work appropriately with each type. For example, look at the methods listed for Mojo's Int type. One such method is __lt__(), which Mojo calls to perform a less-than comparison between two integers (for example, num1 < num2).\n\nLifecycle event handling: These special methods deal with the lifecycle and value ownership of an instance. For example, __init__() and __del__() demarcate the beginning and end of an instance lifetime, and other special methods define the behavior for other lifecycle events such as how to copy or move a value.\n\nYou can learn all about the lifecycle special methods in the Value lifecycle section. However, most structs are simple aggregations of other types, so unless your type requires custom behaviors when an instance is created, copied, moved, or destroyed, you can synthesize the essential lifecycle methods you need (and save yourself some time) by adding the @value decorator.\n\n@value decorator\n\nWhen you add the @value decorator to a struct, Mojo will synthesize the essential lifecycle methods so your object provides full value semantics. Specifically, it generates the __init__(), __copyinit__(), and __moveinit__() methods, which allow you to construct, copy, and move your struct type in a manner that's value semantic and compatible with Mojo's ownership model.\n\nFor example:\n\n@value\nstruct MyPet:\n var name: String\n var age: Int\n\nMojo will notice that you don't have a member-wise initializer, a move constructor, or a copy constructor, and it will synthesize these for you as if you had written:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, owned name: String, age: Int):\n self.name = name^\n self.age = age\n\n fn __copyinit__(inout self, existing: Self):\n self.name = existing.name\n self.age = existing.age\n\n fn __moveinit__(inout self, owned existing: Self):\n self.name = existing.name^\n self.age = existing.age\n\nWithout the copy and move constructors, the following code would not work because Mojo would not know how to copy an instance of MyPet:\n\nvar dog = MyPet('Charlie', 5)\nvar poodle = dog\nprint(poodle.name)\n\nCharlie\n\nWhen you add the @value decorator, Mojo synthesizes each special method above only if it doesn't exist already. That is, you can still implement a custom version of each method.\n\nIn addition to the inout argument convention you already saw with __init__(), this code also introduces owned, which is another argument convention that ensures the argument has unique ownership of the value. For more detail, see the section about value ownership.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/structs",
"description": "Learn about Mojo Structs"
}
]
},
{
"document_id": "7",
"metadata": {
"title": "Mojo's Modules and Packages",
"description": "How to use modules and packages in Mojo.",
"page_count": 1
},
"content":"Modules and packages\n\nMojo provides a packaging system that allows you to organize and compile code libraries into importable files. This page introduces the necessary concepts about how to organize your code into modules and packages (which is a lot like Python), and shows you how to create a packaged binary with the mojo package command.\n\nMojo modules\n\nTo understand Mojo packages, you first need to understand Mojo modules. A Mojo module is a single Mojo source file that includes code suitable for use by other files that import it. For example, you can create a module to define a struct such as this one:\nmymodule.mojo\n\nstruct MyPair:\n var first: Int\n var second: Int\n\n fn __init__(inout self, first: Int, second: Int):\n self.first = first\n self.second = second\n\n fn dump(self):\n print(self.first, self.second)\n\nNotice that this code has no main() function, so you can't execute mymodule.mojo. However, you can import this into another file with a main() function and use it there.\n\nFor example, here's how you can import MyPair into a file named main.mojo that's in the same directory as mymodule.mojo:\nmain.mojo\n\nfrom mymodule import MyPair\n\nfn main():\n var mine = MyPair(2, 4)\n mine.dump()\n\nAlternatively, you can import the whole module and then access its members through the module name. For example:\nmain.mojo\n\nimport mymodule\n\nfn main():\n var mine = mymodule.MyPair(2, 4)\n mine.dump()\n\nYou can also create an alias for an imported member with as, like this:\nmain.mojo\n\nimport mymodule as my\n\nfn main():\n var mine = my.MyPair(2, 4)\n mine.dump()\n\nIn this example, it only works when mymodule.mojo is in the same directory as main.mojo. Currently, you can't import .mojo files as modules if they reside in other directories. That is, unless you treat the directory as a Mojo package, as described in the next section.\nnote\n\nA Mojo module may include a main() function and may also be executable, but that's generally not the practice and modules typically include APIs to be imported and used in other Mojo programs.\n\nMojo packages\n\nA Mojo package is just a collection of Mojo modules in a directory that includes an __init__.mojo file. By organizing modules together in a directory, you can then import all the modules together or individually. Optionally, you can also compile the package into a .mojopkg or .📦 file that's easier to share and still compatible with other system architectures.\n\nYou can import a package and its modules either directly from source files or from a compiled .mojopkg/.📦 file. It makes no real difference to Mojo which way you import a package. When importing from source files, the directory name works as the package name, whereas when importing from a compiled package, the filename is the package name (which you specify with the mojo package command—it can differ from the directory name).\n\nFor example, consider a project with these files:\n\nmain.mojo\nmypackage/\n __init__.mojo\n mymodule.mojo\n\nmymodule.mojo is the same code from examples above (with the MyPair struct) and __init__.mojo is empty.\n\nIn this case, the main.mojo file can now import MyPair through the package name like this:\nmain.mojo\n\nfrom mypackage.mymodule import MyPair\n\nfn main():\n var mine = MyPair(2, 4)\n mine.dump()\n\nNotice that the __init__.mojo is crucial here. If you delete it, then Mojo doesn't recognize the directory as a package and it cannot import mymodule.\n\nThen, let's say you don't want the mypackage source code in the same location as main.mojo. So, you can compile it into a package file like this:\n\nmojo package mypackage -o mypack.mojopkg\n\nnote\n\nA .mojopkg file contains non-elaborated code, so you can share it across systems. The code becomes an architecture-specific executable only after it's imported into a Mojo program that's then compiled with mojo build.\n\nNow, you can move the mypackage source somewhere else, and the project files now look like this:\n\nmain.mojo\nmypack.mojopkg\n\nBecause we named the package file different from the directory, we need to fix the import statement and it all works the same:\nmain.mojo\n\nfrom mypack.mymodule import MyPair\n\nnote\n\nIf you want to rename your package, you cannot simply edit the .mojopkg or .📦 filename, because the package name is encoded in the file. You must instead run mojo package again to specify a new name.\n\nThe __init__ file\n\nAs mentioned above, the __init__.mojo file is required to indicate that a directory should be treated as a Mojo package, and it can be empty.\n\nCurrently, top-level code is not supported in .mojo files, so unlike Python, you can't write code in __init__.mojo that executes upon import. You can, however, add structs and functions, which you can then import from the package name.\n\nHowever, instead of adding APIs in the __init__.mojo file, you can import module members, which has the same effect by making your APIs accessible from the package name, instead of requiring the <package_name>.<module_name> notation.\n\nFor example, again let's say you have these files:\n\nmain.mojo\nmypackage/\n __init__.mojo\n mymodule.mojo\n\nLet's now add the following line in __init__.mojo:\n__init__.mojo\n\nfrom .mymodule import MyPair\n\nThat's all that's in there. Now, we can simplify the import statement in main.mojo like this:\nmain.mojo\n\nfrom mypackage import MyPair\n\nThis feature explains why some members in the Mojo standard library can be imported from their package name, while others required the <package_name>.<module_name> notation. For example, the functional module resides in the algorithm package, so you can import members of that module (such as the map() function) like this:\n\nfrom algorithm.functional import map\n\nHowever, the algorithm/__init__.mojo file also includes these lines:\nalgorithm/__init__.mojo\n\nfrom .functional import *\nfrom .reduction import *\n\nSo you can actually import anything from functional or reduction simply by naming the package. That is, you can drop the functional name from the import statement, and it also works:\n\nfrom algorithm import map\n\nnote\n\nWhich modules in the standard library are imported to the package scope varies, and is subject to change. Refer to the documentation for each module to see how you can import its members.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/packages",
"description": "Learn about Mojo's Modules and Packages"
}
]
}
]
},
{
"section": "Value Ownership",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Intro to Value Ownership",
"description": "How to use value ownership in Mojo.",
"page_count": 1
},
"content":"Intro to value ownership\n\nA program is nothing without data, and all modern programming languages store data in one of two places: the call stack and the heap (also sometimes in CPU registers, but we won't get into that here). However, each language reads and writes data a bit differently—sometimes very differently. So in the following sections, we'll explain how Mojo manages memory in your programs and how this affects the way you write Mojo code.\n\nnote\n\nFor an alternate introduction to ownership in Mojo, check out our two-part blog post: What ownership is really about: a mental model approach, and Deep dive into ownership in Mojo.\n\nStack and heap overview\n\nIn general, all modern programming languages divide a running program's memory into four segments:\n\nText. The compiled program.\nData. Global data, either initialized or uninitialized.\nStack. Local data, automatically managed during the program's runtime.\nHeap. Dynamically-allocated data, managed by the programmer.\n\nThe text and data segments are statically sized, but the stack and heap change size as the program runs.\n\nThe stack stores data local to the current function. When a function is called, the program allocates a block of memory—a stack frame—that is exactly the size required to store the function's data, including any fixed-size local variables. When another function is called, a new stack frame is pushed onto the top of the stack. When a function is done, its stack frame is popped off the stack.\n\nNotice that we said only \"fixed-size local values\" are stored in the stack. Dynamically-sized values that can change in size at runtime are instead stored in the heap, which is a much larger region of memory that allows for dynamic memory allocation. Technically, a local variable for such a value is still stored in the call stack, but its value is a fixed-size pointer to the real value on the heap. Consider a Mojo string: it can be any length, and its length can change at runtime. So the Mojo String struct includes some statically-sized fields, plus a pointer to a dynamically-allocated buffer holding the actual string data.\n\nAnother important difference between the heap and the stack is that the stack is managed automatically—the code to push and pop stack frames is added by the compiler. Heap memory, on the other hand, is managed by the programmer explicitly allocating and deallocating memory. You may do this indirectly—by using standard library types like List and String—or directly, using the UnsafePointer API.\n\nValues that need to outlive the lifetime of a function (such as an array that's passed between functions and should not be copied) are stored in the heap, because heap memory is accessible from anywhere in the call stack, even after the function that created it is removed from the stack. This sort of situation—in which a heap-allocated value is used by multiple functions—is where most memory errors occur, and it's where memory management strategies vary the most between programming languages.\n\nMemory management strategies\n\nBecause memory is limited, it's important that programs remove unused data from the heap (\"free\" the memory) as quickly as possible. Figuring out when to free that memory is pretty complicated.\n\nSome programming languages try to hide the complexities of memory management from you by utilizing a \"garbage collector\" process that tracks all memory usage and deallocates unused heap memory periodically (also known as automatic memory management). A significant benefit of this method is that it relieves developers from the burden of manual memory management, generally avoiding more errors and making developers more productive. However, it incurs a performance cost because the garbage collector interrupts the program's execution, and it might not reclaim memory very quickly.\n\nOther languages require that you manually free data that's allocated on the heap. When done properly, this makes programs execute quickly, because there's no processing time consumed by a garbage collector. However, the challenge with this approach is that programmers make mistakes, especially when multiple parts of the program need access to the same memory—it becomes difficult to know which part of the program \"owns\" the data and must deallocate it. Programmers might accidentally deallocate data before the program is done with it (causing \"use-after-free\" errors), or they might deallocate it twice (\"double free\" errors), or they might never deallocate it (\"leaked memory\" errors). Mistakes like these and others can have catastrophic results for the program, and these bugs are often hard to track down, making it especially important that they don't occur in the first place.\n\nMojo uses a third approach called \"ownership\" that relies on a collection of rules that programmers must follow when passing values. The rules ensure there is only one \"owner\" for a given value at a time. When a value's lifetime ends, Mojo calls its destructor, which is responsible for deallocating any heap memory that needs to be deallocated.\n\nIn this way, Mojo helps ensure memory is freed, but it does so in a way that's deterministic and safe from errors such as use-after-free, double-free and memory leaks. Plus, it does so with a very low performance overhead.\n\nMojo's value ownership model provides an excellent balance of programming productivity and strong memory safety. It only requires that you learn some new syntax and a few rules about how to share access to memory within your program.\n\nBut before we explain the rules and syntax for Mojo's value ownership model, you first need to understand value semantics.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/values",
"description": "Learn about Mojo's Value Ownership"
}
]
},
{
"document_id": "2",
"metadata": {
"title": "Value Semantics",
"description": "Learning about Mojo Value Semantics",
"page_count": 1
},
"content": "Value semantics\n\nMojo doesn't enforce value semantics or reference semantics. It supports them both and allows each type to define how it is created, copied, and moved (if at all). So, if you're building your own type, you can implement it to support value semantics, reference semantics, or a bit of both. That said, Mojo is designed with argument behaviors that default to value semantics, and it provides tight controls for reference semantics that avoid memory errors.\n\nThe controls over reference semantics are provided by the value ownership model, but before we get into the syntax and rules for that, it's important that you understand the principles of value semantics. Generally, it means that each variable has unique access to a value, and any code outside the scope of that variable cannot modify its value.\n\nIntro to value semantics\n\nIn the most basic situation, sharing a value-semantic type means that you create a copy of the value. This is also known as 'pass by value.' For example, consider this code:\n\nx = 1\ny = x\ny += 1\n\nprint(x)\nprint(y)\n\n1\n2\n\nWe assigned the value of x to y, which creates the value for y by making a copy of x. When we increment y, the value of x doesn't change. Each variable has exclusive ownership of a value.\n\nWhereas, if a type instead uses reference semantics, then y would point to the same value as x, and incrementing either one would affect the value for both. Neither x nor y would 'own' the value, and any variable would be allowed to reference it and mutate it.\n\nNumeric values in Mojo are value semantic because they're trivial types, which are cheap to copy.\n\nHere's another example with a function:\n\ndef add_one(y: Int):\n y += 1\n print(y)\n\nx = 1\nadd_one(x)\nprint(x)\n\n2\n1\n\nAgain, the y value is a copy and the function cannot modify the original x value.\n\nIf you're familiar with Python, this is probably familiar so far, because the code above behaves the same in Python. However, Python is not value semantic.\n\nIt gets complicated, but let's consider a situation in which you call a Python function and pass an object with a pointer to a heap-allocated value. Python actually gives that function a reference to your object, which allows the function to mutate the heap-allocated value. This can cause nasty bugs if you're not careful, because the function might incorrectly assume it has unique ownership of that object.\n\nIn Mojo, the default behavior for all function arguments is to use value semantics. If the function wants to modify the value of an incoming argument, then it must explicitly declare so, which avoids accidental mutations of the original value.\n\nAll Mojo types passed to a def function can be treated as mutable, which maintains the expected mutability behavior from Python. But by default, it is mutating a uniquely-owned value, not the original value.\n\nFor example, when you pass an instance of a SIMD vector to a def function it creates a unique copy of all values. Thus, if we modify the argument in the function, the original value is unchanged:\n\ndef update_simd(t: SIMD[DType.int32, 4]):\n t[0] = 9\n print(t)\n\nv = SIMD[DType.int32, 4](1, 2, 3, 4)\nupdate_simd(v)\nprint(v)\n\n[9, 2, 3, 4]\n[1, 2, 3, 4]\n\nIf this were Python code, the function would modify the original object, because Python shares a reference to the original object.\n\nHowever, not all types are inexpensive to copy. Copying a String or List requires allocating heap memory, so we want to avoid copying one by accident. When designing a type like this, ideally you want to prevent implicit copies, and only make a copy when it's explicitly requested.\n\nValue semantics in def vs fn\n\nThe arguments above are mutable because a def function has special treatment for the default borrowed argument convention.\n\nWhereas, fn functions always receive borrowed arguments as immutable references. This is a memory optimization to avoid making unnecessary copies.\n\nFor example, let's create another function with the fn declaration. In this case, the y argument is immutable by default, so if the function wants to modify the value in the local scope, it needs to make a local copy:\n\nfn add_two(y: Int):\n var z = y\n z += 2\n print(z)\n\nx = 1\nadd_two(x)\nprint(x)\n\n3\n1\n\nThis is all consistent with value semantics because each variable maintains unique ownership of its value.\n\nThe way the fn function receives the y value is a 'look but don't touch' approach to value semantics. This is also a more memory-efficient approach when dealing with memory-intensive arguments, because Mojo doesn't make any copies unless we explicitly make the copies ourselves.\n\nThus, the default behavior for def and fn arguments is fully value semantic: arguments are either copies or immutable references, and any living variable from the callee is not affected by the function.\n\nBut we must also allow reference semantics (mutable references) because it's how we build performant and memory-efficient programs (making copies of everything gets really expensive). The challenge is to introduce reference semantics in a way that does not disturb the predictability and safety of value semantics.\n\nThe way we do that in Mojo is, instead of enforcing that every variable have 'exclusive access' to a value, we ensure that every value has an 'exclusive owner,' and destroy each value when the lifetime of its owner ends.\n\nOn the next page about value ownership, you'll learn how to modify the default argument conventions, and safely use reference semantics so every value has only one owner at a time.\n\nPython-style reference semantics\n\nnote\n\nIf you will always use strict type declarations, you can skip this section because it only applies to Mojo code using def functions without type declarations (or values declared as object).\n\nAs we said at the top of this page, Mojo doesn't enforce value semantics or reference semantics. It's up to each type author to decide how an instance of their type should be created, copied, and moved (see Value lifecycle). Thus, in order to provide compatibility with Python, Mojo's object type is designed to support Python's style of argument passing for functions, which is different from the other types in Mojo.\n\nPython's argument-passing convention is called 'pass by object reference.' This means when you pass a variable to a Python function, you actually pass a reference to the object, as a value (so it's not strictly reference semantics).\n\nPassing the object reference 'as a value' means that the argument name is just a container that acts like an alias to the original object. If you reassign the argument inside the function, it does not affect the caller's original value. However, if you modify the object itself (such as call append() on a list), the change is visible to the original object outside the function.\n\nFor example, here's a Python function that receives a list and modifies it:\n\n%%python\ndef modify_list(l):\n l.append(3)\n print('func:', l)\n\nar = [1, 2]\nmodify_list(ar)\nprint('orig:', ar)\n\nfunc: [1, 2, 3]\norig: [1, 2, 3]\n\nIn this example, it looks like the list is 'passed by reference' because l modifies the original value.\n\nHowever, if the Python function instead assigns a value to l, it does not affect the original value:\n\n%%python\ndef change_list(l):\n l = [3, 4]\n print('func:', l)\n\nar = [1, 2]\nchange_list(ar)\nprint('orig:', ar)\n\nfunc: [3, 4]\norig: [1, 2]\n\nThis demonstrates how a Python argument holds the object reference as a value: the function can mutate the original value, but it can also assign a new object to the argument name.\n\nPass by object reference in Mojo\n\nAlthough we haven't finished implementing the object type to represent any Mojo type, our intention is to do so, and enable 'pass by object reference' as described above for all dynamic types in a def function.\n\nThat means you can have dynamic typing and 'pass by object reference' behavior by simply writing your Mojo code like Python:\n\nUse def function declarations.\nDon't declare argument types.\n\nTODO\n\nMojo is not a complete superset of Python yet, and there is a lot to do in this department before Mojo supports all of Python's types and behaviors. As such, this is a topic that also still needs a lot of documentation.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/values/value-semantics",
"description": "Learn about Mojo Value Semantics"
}
]
},
{
"document_id": "3",
"metadata": {
"title": "Ownership and Borrowing",
"description": "Using Ownership and Borrowing in Mojo",
"page_count": 1
},
"content": "Ownership and borrowing\n\nA challenge you might face when using some programming languages is that you must manually allocate and deallocate memory. When multiple parts of the program need access to the same memory, it becomes difficult to keep track of who 'owns' a value and determine when is the right time to deallocate it. If you make a mistake, it can result in a 'use-after-free' error, a 'double free' error, or a 'leaked memory' error, any one of which can be catastrophic.\n\nMojo helps avoid these errors by ensuring there is only one variable that owns each value at a time, while still allowing you to share references with other functions. When the life span of the owner ends, Mojo destroys the value. Programmers are still responsible for making sure any type that allocates resources (including memory) also deallocates those resources in its destructor. Mojo's ownership system ensures that destructors are called promptly.\n\nOn this page, we'll explain the rules that govern this ownership model, and how to specify different argument conventions that define how values are passed into functions.\n\nArgument conventions\n\nIn all programming languages, code quality and performance is heavily dependent upon how functions treat argument values. That is, whether a value received by a function is a unique value or a reference, and whether it's mutable or immutable, has a series of consequences that define the readability, performance, and safety of the language.\n\nIn Mojo, we want to provide full value semantics by default, which provides consistent and predictable behavior. But as a systems programming language, we also need to offer full control over memory optimizations, which generally requires reference semantics. The trick is to introduce reference semantics in a way that ensures all code is memory safe by tracking the lifetime of every value and destroying each one at the right time (and only once). All of this is made possible in Mojo through the use of argument conventions that ensure every value has only one owner at a time.\n\nAn argument convention specifies whether an argument is mutable or immutable, and whether the function owns the value. Each convention is defined by a keyword at the beginning of an argument declaration:\n\nborrowed: The function receives an immutable reference. This means the function can read the original value (it is not a copy), but it cannot mutate (modify) it. def functions treat this differently, as described below.\ninout: The function receives a mutable reference. This means the function can read and mutate the original value (it is not a copy).\nowned: The function takes ownership. This means the function has exclusive ownership of the argument. Often, this also implies that the caller should transfer ownership to this function, but that's not always what happens and this might instead be a copy (as you'll learn below).\nref: The function gets a reference with an associated lifetime. The reference can be either mutable or immutable. You can think of ref arguments as a generalization of the borrowed and inout conventions. ref arguments are an advanced topic, and they're described in more detail in Lifetimes and references.\n\nFor example, this function has one argument that's a mutable reference and one that's immutable:\n\nfn add(inout x: Int, borrowed y: Int):\n x += y\n\nfn main():\n var a = 1\n var b = 2\n add(a, b)\n print(a) # Prints 3\n\nYou've probably already seen some function arguments that don't declare a convention. by default, all arguments are borrowed. But def and fn functions treat borrowed arguments somewhat differently:\n\nIn an fn function, the function always receives an immutable reference. If you want a mutable copy, you can assign it to a local variable:\n\nvar my_copy = borrowed_arg\n\nIn a def function, if the function mutates the value, the function receives a mutable copy of the argument. Otherwise, it receives an immutable reference. This allows you to treat arguments as mutable, but avoid the overhead of making extra copies when they're not needed.\n\nThe difference between borrowed and owned in a def function may be a little subtle:\n\nIn a def function, a borrowed argument is received as an immutable reference, unless it's mutated in the body of the function. This eliminates unneeded copies, but maintains the Python expectation that arguments are mutable.\n\nThe borrowed argument always gets an immutable reference or a local copy. You can't transfer a value into a borrowed argument.\n\nThe owned argument always gets a uniquely owned value, which may have been copied or transferred from the callee. Using owned arguments without the transfer sigil (^) usually results in values being copied.\n\nIn the following sections, we'll explain each of these argument conventions in more detail.\n\nOwnership summary\n\nThe fundamental rules that make Mojo's ownership model work are the following:\n\nEvery value has only one owner at a time.\nWhen the lifetime of the owner ends, Mojo destroys the value.\nIf there are outstanding references to a value, Mojo keeps the value alive.\n\nIn the future, the Mojo lifetime checker will enforce reference exclusivity, so that only one mutable reference to a value can exist at a time. This is not currently enforced.\n\nBorrowed arguments (borrowed)\n\nThe borrowed convention is the default for all arguments.\n\nIn fn functions, a borrowed argument is received as an immutable reference.\n\nIn def functions, you can treat a borrowed argument as mutable or immutable. If you mutate the argument in the body of the function, you get a mutable copy of the original value. If you don't mutate the argument, you get an immutable reference, as in an fn function.\n\nFor example:\n\nfrom collections import List\ndef print_list(list: List[Int]):\n print(list.__str__())\n\nvar list = List(1, 2, 3, 4)\nprint_list(list)\n\n[1, 2, 3, 4]\n\nHere the list argument to print_list() is borrowed and not mutated, so the print_list() function gets an immutable reference to the original List, and doesn't do any copying.\n\nIn general, passing an immutable reference is much more efficient when handling large or expensive-to-copy values, because the copy constructor and destructor are not invoked for a borrow.\n\nTo avoid expensive copies, types should only be implicitly copyable if the copy operation is inexpensive.\n\nCompared to C++ and Rust\n\nMojo's borrowed argument convention is similar in some ways to passing an argument by const& in C++, which also avoids a copy of the value and disables mutability in the callee. However, the borrowed convention differs from const& in C++ in two important ways:\n\nThe Mojo compiler implements a lifetime checker that ensures that values are not destroyed when there are outstanding references to those values.\n\nSmall values like Int, Float, and SIMD are passed directly in machine registers instead of through an extra indirection (this is because they are declared with the @register_passable decorator). This is a significant performance enhancement when compared to languages like C++ and Rust, and moves this optimization from every call site to a declaration on the type definition.\n\nIn the future, Mojo's lifetime checker will enforce the exclusivity of mutable references, similar to Rust. The major difference between Rust and Mojo is that Mojo does not require a sigil on the caller side to pass by borrow. Also, Mojo is more efficient when passing small values, and Rust defaults to moving values instead of passing them around by borrow. These policy and syntax decisions allow Mojo to provide an easier-to-use programming model.\n\nMutable arguments (inout)\n\nIf you'd like your function to receive a mutable reference, add the inout keyword in front of the argument name. You can think of inout like this: it means any changes to the value inside the function are visible outside the function.\n\nFor example, this mutate() function updates the original list value:\n\nfrom collections import List\ndef mutate(inout l: List[Int]):\n l.append(5)\n\nvar list = List(1, 2, 3, 4)\nmutate(list)\nprint_list(list)\n\n[1, 2, 3, 4, 5]\n\nThat behaves like an optimized replacement for this:\n\nfrom collections import List\ndef mutate_copy(l: List[Int]) -> List[Int]:\n l.append(5)\n return l\n\nvar list = List(1, 2, 3, 4)\nlist = mutate_copy(list)\nprint_list(list)\n\n[1, 2, 3, 4, 5]\n\nAlthough the code using inout isn't that much shorter, it's more memory efficient because it does not make a copy of the value.\n\nHowever, remember that the values passed as inout must already be mutable. For example, if you try to take a borrowed value and pass it to another function as inout, you'll get a compiler error because Mojo can't form a mutable reference from an immutable reference.\n\nnote\n\nYou cannot define default values for inout arguments.\n\nArgument exclusivity\n\nMojo enforces argument exclusivity for mutable references. This means that if a function receives a mutable reference to a value (such as an inout argument), it can't receive any other references to the same value—mutable or immutable. That is, a mutable reference can't have any other references that alias it.\n\nFor example, consider the following code example:\n\nfn append_twice(inout s: String, other: String):\n s += other\n s += other\n\nfn invalid_access():\n var my_string = str('o')\n append_twice(my_string, my_string)\n print(my_string)\n\nThis code is confusing because the user might expect the output to be ooo, but since the first addition mutates both s and other, the actual output would be oooo. Enforcing exclusivity of mutable references not only prevents coding errors, it also allows the Mojo compiler to optimize code in some cases.\n\nOne way to avoid this issue when you do need both a mutable and an immutable reference (or need to pass the same value to two arguments) is to make a copy:\n\nfn valid_access():\n var my_string = str('o')\n var other_string = str(my_string)\n append_twice(my_string, other_string)\n print(my_string)\n\nOnly a warning\n\nAliasing a mutable reference produces a warning in v24.5. This will change to an error in a subsequent release.\n\nTransfer arguments (owned and ^)\n\nAnd finally, if you'd like your function to receive value ownership, add the owned keyword in front of the argument name.\n\nThis convention is often combined with use of the postfixed ^ 'transfer' sigil on the variable that is passed into the function, which ends the lifetime of that variable.\n\nTechnically, the owned keyword does not guarantee that the received value is the original value—it guarantees only that the function gets unique ownership of a value. This happens in one of three ways:\n\nThe caller passes the argument with the ^ transfer sigil, which ends the lifetime of that variable (the variable becomes uninitialized) and ownership is transferred into the function without making a copy of any heap-allocated data.\nThe caller does not use the ^ transfer sigil, in which case, the value is copied into the function argument and the original variable remains valid. (If the original value is not used again, the compiler may optimize away the copy and transfer the value).\nThe caller passes in a newly-created 'owned' value, such as a value returned from a function. In this case, no variable owns the value and it can be transferred directly to the callee.\n\nFor example:\n\ndef take(owned s: String):\n pass\n\ntake(str('A brand-new String!'))\n\nFor example, the following code works by making a copy of the string, because—although take_text() uses the owned convention—the caller does not include the transfer sigil:\n\nfn take_text(owned text: String):\n text += '!'\n print(text)\n\nfn my_function():\n var message: String = 'Hello'\n take_text(message)\n print(message)\n\nmy_function()\n\nHello!\nHello\n\nHowever, if you add the ^ transfer sigil when calling take_text(), the compiler complains about print(message), because at that point, the message variable is no longer initialized. That is, this version does not compile:\n\nfn my_function():\n var message: String = 'Hello'\n take_text(message^)\n print(message) # ERROR: The `message` variable is uninitialized\n\nThis is a critical feature of Mojo's lifetime checker, because it ensures that no two variables can have ownership of the same value. To fix the error, you must not use the message variable after you end its lifetime with the ^ transfer operator. So here is the corrected code:\n\nfn my_function():\n var message: String = 'Hello'\n take_text(message^)\n\nmy_function()\n\nHello!\n\nRegardless of how it receives the value, when the function declares an argument as owned, it can be certain that it has unique mutable access to that value. Because the value is owned, the value is destroyed when the function exits—unless the function transfers the value elsewhere.\n\nFor example, in the following example, add_to_list() takes a string and appends it to the list. Ownership of the string is transferred to the list, so it's not destroyed when the function exits. On the other hand, consume_string() doesn't transfer its owned value out, so the value is destroyed at the end of the function.\n\nfrom collections import List\ndef add_to_list(owned name: String, inout list: List[String]):\n list.append(name^)\n\ndef consume_string(owned s: String):\n print(s)\n\nnote\n\nValue lifetimes are not fully implemented for top-level code in Mojo's REPL, so the transfer sigil currently works as intended only when used inside a function.\n\nTransfer implementation details\n\nIn Mojo, you shouldn't conflate 'ownership transfer' with a 'move operation'—these are not strictly the same thing.\n\nThere are multiple ways that Mojo can transfer ownership of a value:\n\nIf a type implements the move constructor, __moveinit__(), Mojo may invoke this method if a value of that type is transferred into a function as an owned argument, and the original variable's lifetime ends at the same point (with or without use of the ^ transfer operator).\nIf a type implements the copy constructor, __copyinit__() and not __moveinit__(), Mojo may copy the value and destroy the old value.\nIn some cases, Mojo can optimize away the move operation entirely, leaving the value in the same memory location but updating its ownership. In these cases, a value can be transferred without invoking either the __copyinit__() or __moveinit__() constructors.\n\nIn order for the owned convention to work without the transfer sigil, the value type must be copyable (via __copyinit__()).\n\nComparing def and fn argument conventions\n\nAs mentioned in the section about functions, def and fn functions are interchangeable, as far as a caller is concerned, and they can both accomplish the same things. It's only the inside that differs, and Mojo's def function is essentially just sugaring for the fn function:\n\nA def argument without a type annotation defaults to object type (whereas as fn requires all types be explicitly declared).\nA def function can treat a borrowed argument as mutable (in which case it receives a mutable copy). An fn function must make this copy explicitly.\n\nFor example, these two functions have the exact same behavior.\n\ndef def_example(a: Int, inout b: Int, owned c):\n pass\n\nfn fn_example(a_in: Int, inout b: Int, owned c: object):\n var a = a_in\n pass\n\nThis shadow copy typically adds no overhead, because small types like object are cheap to copy. However, copying large types that allocate heap storage can be expensive. (For example, copying List or Dict types, or copying large numbers of strings.)",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/values/ownership",
"description": "Ownership and Borrowing in Mojo"
}
]
},
{
"document_id": "4",
"metadata": {
"title": "Lifetimes and References",
"description": "Using Lifetimes and References in Mojo",
"page_count": 1
},
"content": "Lifetimes and references\nWork in progress\n\nBoth lifetimes and references are a work in progress and subject to change in future releases.\n\nIn Mojo, lifetime has two meanings:\n\nIn general terms, a value's lifetime refers to the span of time when the value is valid.\nIt also refers to a specific type of parameter value used to help track the lifetimes of values and references to values. For clarity, we'll use lifetime in code font to refer to the type.\n\nThe Mojo compiler includes a lifetime checker, a compiler pass that analyzes dataflow through your program. It identifies when variables are valid and inserts destructor calls when a value's lifetime ends.\n\nThe Mojo compiler uses lifetime values to track the validity of references. Specifically, a lifetime value answers two questions:\n\nWhat logical storage location 'owns' this value?\nCan the value be mutated using this reference?\n\nFor example, consider the following code:\n\nfn print_str(s: String):\n print(s)\n\nname = String('Joan')\nprint_str(name)\n\nJoan\n\nThe line name = String('Joan') declares a variable with an identifier (name) and logical storage space for a String value. When you pass name into the print_str() function, the function gets an immutable reference to the value. So both name and s refer to the same logical storage space, and have associated lifetime values that lets the Mojo compiler reason about them.\n\nMost of the time, lifetime values are handled automatically by the compiler. However, in some cases you'll need to interact with lifetime values directly:\n\nWhen working with references—specifically ref arguments and ref return values.\nWhen working with types like Reference or Span which are parameterized on the lifetime of the data they refer to.\n\nThis section covers ref arguments and ref return values, which let functions take arguments and provide return values as references with parametric lifetimes.\n\nWorking with lifetimes\n\nMojo's lifetime values are unlike most other values in the language, because they're primitive values, not Mojo structs. Specifying a parameter that takes a lifetime value, you can't just say, l: Lifetime, because there's no Lifetime type. Likewise, because these values are mostly created by the compiler, you can't just create your own lifetime value—you usually need to derive a lifetime from an existing value.\n\nLifetime types\n\nMojo supplies a struct and a set of aliases that you can use to specify lifetime types. As the names suggest, the ImmutableLifetime and MutableLifetime aliases represent immutable and mutable lifetimes, respectively:\n\nstruct ImmutableRef[lifetime: ImmutableLifetime]:\n pass\n\nOr you can use the AnyLifetime struct to specify a lifetime with parametric mutability:\n\nstruct ParametricRef[\n is_mutable: Bool,\n lifetime: AnyLifetime[is_mutable].type\n]:\n pass\n\nNote that AnyLifetime isn't a lifetime value, it's a helper for specifying a lifetime type. Lifetime types carry the mutability of a reference as a boolean parameter value, indicating whether the lifetime is mutable, immutable, or even with mutability depending on a parameter specified by the enclosing API.\n\nThe is_mutable parameter here is an infer-only parameter. It's never specified directly by the user, but always inferred from context. The lifetime value is often inferred, as well. For example, the following code creates a Reference to an existing value, but doesn't need to specify a lifetime—the lifetime is inferred from the variable passed in to the reference.\n\nfrom memory import Reference\n\ndef use_reference():\n a = 10\n r = Reference(a)\n\nLifetime values\n\nMost lifetime values are created by the compiler. As a developer, there are a few ways to specify lifetime values:\n\nStatic lifetimes. The ImmutableStaticLifetime and MutableStaticLifetime aliases are lifetimes that last for the duration of the program.\nThe __lifetime_of() magic function, which returns the lifetime associated with the value (or values) passed in.\nInferred lifetime. You can use inferred parameters to capture the lifetime of a value passed in to a function.\n\nStatic lifetimes\n\nYou can use the static lifetimes ImmutableStaticLifetime and MutableStaticLifetime when you have a value that should never be destroyed; or when there's no way to construct a meaningful lifetime for a value.\n\nFor an example of the first case, the StringLiteral method as_string_slice() returns a StringSlice pointing to the original string literal. String literals are static—they're allocated at compile time and never destroyed—so the slice is created with an immutable, static lifetime.\n\nConverting an UnsafePointer into a Reference is an example of the second case: the UnsafePointer's data doesn't carry a lifetime—one reason that it's considered unsafe—but you need to specify a lifetime when creating a Reference. In this case, there's no way to construct a meaningful lifetime value, so the new Reference is constructed with a MutableStaticLifetime. Mojo won't destroy this value automatically. As with any value stored using a pointer, it's up to the user to explicitly destroy the value.\n\nDerived lifetimes\n\nUse the __lifetime_of() magic function to obtain a value's lifetime. This can be useful, for example, when creating a container type. Consider the List type. Subscripting into a list (list[4]) returns a reference to the item at the specified position. The signature of the __getitem__() method that's called to return the subscripted item looks like this:\n\nfn __getitem__(ref [_]self, idx: Int) -> ref [__lifetime_of(self)] T:\n\nThe syntax may be unfamiliar—ref arguments and ref return values are described in the following sections. For now it's enough to know that the return value is a reference of type T (where T is the element type stored in the list), and the reference has the same lifetime as the list itself. This means that as long as you hold the reference, the underlying list won't be destroyed.\n\nnote\n\nIdeally the returned reference's lifetime would be linked to the individual list item, rather than the list itself. Mojo doesn't yet have a mechanism to express this relationship.\n\nInferred lifetimes\n\nThe other common way to access a lifetime value is to infer it from the the arguments passed to a function or method. For example, the Span type has an associated lifetime:\n\nstruct Span[\n is_mutable: Bool,\n T: CollectionElement,\n lifetime: AnyLifetime[is_mutable].type,\n](CollectionElementNew):\n 'A non owning view of contiguous data.'\n\nOne of its constructors creates a Span from an existing List, and infers its lifetime value from the list:\n\nfn __init__(inout self, ref [lifetime]list: List[T, *_]):\n 'Construct a Span from a List.'\n self._data = list.data\n self._len = len(list)\n\nWorking with references\n\nYou can use the ref keyword with arguments and return values to specify a reference with parametric mutability. That is, they can be either mutable or immutable.\n\nThese references shouldn't be confused with the Reference type, which is basically a safe pointer type. A Reference needs to be dereferenced, like a pointer, to access the underlying value. A ref argument, on the other hand, looks like a borrowed or inout argument inside the function. A ref return value looks like any other return value to the calling function, but it is a reference to an existing value, not a copy.\n\nref arguments\n\nThe ref argument convention lets you specify an argument of parametric mutability: that is, you don't need to know in advance whether the passed argument will be mutable or immutable. There are several reasons you might want to use a ref argument:\n\nYou want to accept an argument with parametric mutability.\nYou want to tie the lifetime of one argument to the lifetime of another argument.\nWhen you want an argument that is guaranteed to be passed in memory: this can be important and useful for generic arguments that need an identity, irrespective of whether the concrete type is register passable.\n\nThe syntax for a ref argument is:\n\nref [lifetime] argName: argType\n\nThe lifetime parameter passed inside the square brackets can be replaced with an underscore character (_) to indicate that the parameter is unbound. Think of it as a wildcard that will accept any lifetime:\n\ndef add_ref(ref [_] a: Int, b: Int) -> Int:\n return a+b\n\nYou can also name the lifetime explicitly. This is useful if you want to specify an ImmutableLifetime or MutableLifetime, or if you want to bind to the is_mutable parameter.\n\ndef take_str_ref[\n is_mutable: Bool,\n life: AnyLifetime[is_mutable].type\n ](ref [life] s: String):\n @parameter\n if is_mutable:\n print('Mutable: ' + s)\n else:\n print('Immutable: ' + s)\n\ndef pass_refs(s1: String, owned s2: String):\n take_str_ref(s1)\n take_str_ref(s2)\n\npass_refs('Hello', 'Goodbye')\n\nImmutable: Hello\nMutable: Goodbye\n\nref return values\n\nLike ref arguments, ref return values allow a function to return a mutable or immutable reference to a value. Like a borrowed or inout argument, these references don't need to be dereferenced.\n\nref return values can be an efficient way to handle updating items in a collection. The standard way to do this is by implementing the __getitem__() and __setitem__() dunder methods. These are invoked to read from and write to a subscripted item in a collection:\n\nvalue = list[a]\nlist[b] += 10\n\nWith a ref argument, __getitem__() can return a mutable reference that can be modified directly. This has pros and cons compared to using a __setitem__() method:\n\nThe mutable reference is more efficient—a single update isn't broken up across two methods. However, the referenced value must be in memory.\nA __getitem__()/__setitem__() pair allows for arbitrary to be run when values are retrieved and set. For example, __setitem__() can validate or constrain input values.\n\nFor example, in the following example, NameList has a get() method that returns a reference:\n\nstruct NameList:\n var names: List[String]\n\ndef __init__(inout self, *names: String):\n self.names = List[String]()\n for name in names:\n self.names.append(name[])\n\ndef __getitem__(ref [_] self: Self, index: Int) ->\n ref [__lifetime_of(self)] String:\n if (index >=0 and index < len(self.names)):\n return self.names[index]\n else:\n raise Error('index out of bounds')\n\ndef use_name_list():\n list = NameList('Thor', 'Athena', 'Dana', 'Vrinda')\n print(list[2])\n list[2] += '?'\n print(list[2])\n\nuse_name_list()\n\nDana\nDana?\n\nNote that this update succeeds, even though NameList doesn't define a __setitem__() method:\n\nlist[2] += '?'\n\nAlso note that the code uses the return value directly each time, rather than assigning the return value to a variable, like this:\n\nname = list[2]\n\nSince a variable needs to own its value, name would end up with an owned copy of the value that list[2] returns. Mojo doesn't currently have syntax to express that you want to keep the original reference in name. This will be added in a future release.\n\nIn cases where you need to be able to assign the return value to a variable—for example, an iterator which will be used in a for..in loop—you might consider returning a Reference instead of a ref return value. For example, see the iterator for the List type. You can assign a Reference to a variable, but you need to use the dereference operator ([]) to access the underlying value.\n\nnums = List(1, 2, 3)\nfor item in nums: # List iterator returns a Reference\n print(item[])\n\n1\n2\n3\n\nParametric mutability of return values\n\nAnother advantage of ref return arguments is the ability to support parametric mutability. For example, recall the signature of the __getitem__() method above:\n\ndef __getitem__(ref [_] self: Self, index: Int) ->\n ref [__lifetime_of(self)] String:\n\nSince the lifetime of the return value is tied to the lifetime of self, the returned reference will be mutable if the method was called using a mutable reference. The method still works if you have an immutable reference to the NameList, but it returns an immutable reference:\n\nfn pass_immutable_list(list: NameList) raises:\n print(list[2])\n # list[2] += '?' # Error, this list is immutable\n\ndef use_name_list_again():\n list = NameList('Sophie', 'Jack', 'Diana')\n pass_immutable_list(list)\n\nuse_name_list_again()\n\nDiana\n\nWithout parametric mutability, you'd need to write two versions of __getitem__(), one that accepts an immutable self and another that accepts a mutable self.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/values/lifetimes",
"description": "Lifetimes and References in Mojo"
}
]
}
]
},
{
"section": "Value Lifecycle",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Intro to Value Lifecycle",
"description": "Gaining an introductory understanding of value lifecycle in Mojo",
"page_count": 1
},
"content": "Intro to value lifecycle\n\nSo far, we've explained how Mojo allows you to build high-performance code that is memory safe without manually managing memory, using Mojo's ownership model. However, Mojo is designed for systems programming, which often requires manual memory management for custom data types. So, Mojo lets you do that as you see fit. To be clear, Mojo has no reference counter and no garbage collector.\n\nMojo also has no built-in data types with special privileges. All data types in the standard library (such as Bool, Int, and String) are implemented as structs. You can actually write your own replacements for these types by using low-level primitives provided by MLIR dialects.\n\nWhat's great about the Mojo language is that it provides you these low-level tools for systems programming, but within a framework that helps you build things that are safe and easy to use from higher-level programs. That is, you can get under the hood and write all the 'unsafe' code you want, but as long as you do so in accordance with Mojo's value semantics, the programmer instantiating your type/object doesn't need to think about memory management at all, and the behavior will be safe and predictable, thanks to value ownership.\n\nIn summary, it's the responsibility of the type author to manage the memory and resources for each value type, by implementing specific lifecycle methods, such as the constructor, copy constructor, move constructor, and destructor, as necessary. Mojo doesn't create any constructors by default, although it does add a trivial, no-op destructor for types that don't define their own.\n\nIn the following pages, we'll explain exactly how to define these lifecycle methods in accordance with value semantics so your types play nicely with value ownership.\n\nLifecycles and lifetimes\n\nFirst, let's clarify some terminology:\n\nThe 'lifecycle' of a value is defined by various dunder methods in a struct. Each lifecycle event is handled by a different method, such as the constructor (__init__()), the destructor (__del__()), the copy constructor (__copyinit__()), and the move constructor (__moveinit__()). All values that are declared with the same type have the same lifecycle.\n\nThe 'lifetime' of a value is defined by the span of time during program execution in which each value is considered valid. The life of a value begins when it is initialized (via __init__(), __copyinit__() or __moveinit__()) and ends when it is destroyed (__del__()), or consumed in some other way (for example, as part of a __moveinit__() call).\n\nNo two values have the exact same life span, because every value is created and destroyed at a different point in time (even if the difference is imperceptible).\n\nLifetime type\n\nThe concept of lifetimes is related to the lifetime type, a Mojo primitive used to track ownership. For most Mojo programming, you won't need to work with lifetime values directly. For information, see Lifetimes and references.\n\nThe life of a value in Mojo begins when a variable is initialized and continues up until the value is last used, at which point Mojo destroys it. Mojo destroys every value/object as soon as it's no longer used, using an 'as soon as possible' (ASAP) destruction policy that runs after every sub-expression. The Mojo compiler takes care of releasing resources after last use when needed.\n\nAs you might imagine, keeping track of a value's life can be difficult if a value is shared across functions many times during the life of a program. However, Mojo makes this predictable partly through its value semantics and value ownership (both prerequisite readings for the following sections). The final piece of the puzzle for lifetime management is the value lifecycle: every value (defined in a struct) needs to implement key lifecycle methods that define how a value is created and destroyed.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/lifecycle",
"description": "Introduction to Value Lifecycle's in Mojo"
}
]
},
{
"document_id": "2",
"metadata": {
"title": "Life of a Value",
"description": "A deeper dive into the life of a value in Mojo",
"page_count": 1
},
"content": "Life of a value\n\nThe life of a value in Mojo begins when a variable is initialized and continues up until the value is last used, at which point Mojo destroys it. This page describes how every value in Mojo is created, copied, and moved. (The next page describes how values are destroyed.)\n\nAll data types in Mojo—including basic types in the standard library such as Bool, Int, and String, up to complex types such as SIMD and object—are defined as a struct. This means the creation and destruction of any piece of data follows the same lifecycle rules, and you can define your own data types that work exactly the same way.\n\nMojo structs don't get any default lifecycle methods, such as a constructor, copy constructor, or move constructor. That means you can create a struct without a constructor, but then you can't instantiate it, and it would be useful only as a sort of namespace for static methods. For example:\n\nstruct NoInstances:\n var state: Int\n\n @staticmethod\n fn print_hello():\n print('Hello world!')\n\nWithout a constructor, this cannot be instantiated, so it has no lifecycle. The state field is also useless because it cannot be initialized (Mojo structs do not support default field values—you must initialize them in a constructor).\n\nSo the only thing you can do is call the static method:\n\nNoInstances.print_hello()\n\nHello world!\n\nConstructor\n\nTo create an instance of a Mojo type, it needs the __init__() constructor method. The main responsibility of the constructor is to initialize all fields. For example:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, name: String, age: Int):\n self.name = name\n self.age = age\n\nNow we can create an instance:\n\nvar mine = MyPet('Loki', 4)\n\nAn instance of MyPet can also be borrowed and destroyed, but it currently can't be copied or moved.\n\nWe believe this is a good default starting point, because there are no built-in lifecycle events and no surprise behaviors. You—the type author—must explicitly decide whether and how the type can be copied or moved, by implementing the copy and move constructors.\n\nnote\n\nMojo does not require a destructor to destroy an object. As long as all fields in the struct are destructible (every type in the standard library is destructible, except for pointers), then Mojo knows how to destroy the type when its lifetime ends. We'll discuss that more in Death of a value.\n\nOverloading the constructor\n\nLike any other function/method, you can overload the __init__() constructor to initialize the object with different arguments. For example, you might want a default constructor that sets some default values and takes no arguments, and then additional constructors that accept more arguments.\n\nJust be aware that, in order to modify any fields, each constructor must declare the self argument with the inout convention. If you want to call one constructor from another, you simply call upon that constructor as you would externally (you don't need to pass self).\n\nFor example, here's how you can delegate work from an overloaded constructor:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self):\n self.name = ''\n self.age = 0\n\n fn __init__(inout self, name: String):\n self = MyPet()\n self.name = name\n\nField initialization\n\nNotice in the previous example that, by the end of each constructor, all fields must be initialized. That's the only requirement in the constructor.\n\nIn fact, the __init__() constructor is smart enough to treat the self object as fully initialized even before the constructor is finished, as long as all fields are initialized. For example, this constructor can pass around self as soon as all fields are initialized:\n\nfn use(arg: MyPet):\n pass\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, name: String, age: Int, cond: Bool):\n self.name = name\n if cond:\n self.age = age\n use(self) # Safe to use immediately!\n\n self.age = age\n use(self) # Safe to use immediately!\n\nConstructors and implicit conversion\n\nMojo supports implicit conversion from one type to another. Implicit conversion can happen when one of the following occurs:\n\nYou assign a value of one type to a variable with a different type.\nYou pass a value of one type to a function that requires a different type.\n\nIn both cases, implicit conversion is supported when the target type defines a constructor that takes a single required, non-keyword argument of the source type. For example:\n\nvar a = Source()\nvar b: Target = a\n\nMojo implicitly converts the Source value in a to a Target value if Target defines a matching constructor like this:\n\nstruct Target:\n fn __init__(inout self, s: Source): ...\n\nWith implicit conversion, the assignment above is essentially identical to:\n\nvar b = Target(a)\n\nThe constructor used for implicit conversion can take optional arguments, so the following constructor would also support implicit conversion from Source to Target:\n\nstruct Target:\n fn __init__(inout self, s: Source, reverse: Bool = False): ...\n\nImplicit conversion also occurs if the type doesn't declare its own constructor, but instead uses the @value decorator, and the type has only one field. That's because Mojo automatically creates a member-wise constructor for each field, and when there is only one field, that synthesized constructor works exactly like a conversion constructor. For example, this type also can convert a Source value to a Target value:\n\n@value\nstruct Target:\n var s: Source\n\nImplicit conversion can fail if Mojo can't unambiguously match the conversion to a constructor. For example, if the target type has two overloaded constructors that take different types, and each of those types supports an implicit conversion from the source type, the compiler has two equally-valid paths to convert the values:\n\nstruct A: \n fn __init__(inout self, s: Source): ...\n\nstruct B: \n fn __init__(inout self, s: Source): ...\n\nstruct Target:\n fn __init__(inout self, a: A): ...\n fn __init__(inout self, b: B): ...\n\n# Fails\nvar t = Target(Source())\n\nIn this case, removing either one of the target type's constructors will fix the problem.\n\nIf you want to define a single-argument constructor, but you don't want the types to implicitly convert, you can define the constructor with a keyword-only argument:\n\nstruct Target:\n # does not support implicit conversion\n fn __init__(inout self, *, source: Source): ...\n\n# the constructor must be called with a keyword\nvar t = Target(source=a)\n\nnote\n\nIn the future we intend to provide a more explicit method of declaring whether a constructor should support implicit conversion.\n\nCopy constructor\n\nWhen Mojo encounters an assignment operator (=), it tries to make a copy of the right-side value by calling upon that type's copy constructor: the __copyinit__() method. Thus, it's the responsibility of the type author to implement __copyinit__() so it returns a copy of the value.\n\nFor example, the MyPet type above does not have a copy constructor, so this code fails to compile:\n\nvar mine = MyPet('Loki', 4)\nvar yours = mine # This requires a copy, but MyPet has no copy constructor\n\nTo make it work, we need to add the copy constructor, like this:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, name: String, age: Int):\n self.name = name\n self.age = age\n\n fn __copyinit__(inout self, existing: Self):\n self.name = existing.name\n self.age = existing.age\n\nnote\n\nSelf (capital 'S') is an alias for the current type name (MyPet, in this example). Using this alias is a best practice to avoid any mistakes when referring to the current struct name.\n\nAlso, notice that the existing argument in __copyinit__() is immutable because the default argument convention in an fn function is borrowed—this is a good thing because this function should not modify the contents of the value being copied.\n\nNow this code works to make a copy:\n\nvar mine = MyPet('Loki', 4)\nvar yours = mine\n\nWhat makes Mojo's copy behavior different, compared to other languages, is that __copyinit__() is designed to perform a deep copy of all fields in the type (as per value semantics). That is, it copies heap-allocated values, rather than just copying the pointer.\n\nHowever, the Mojo compiler doesn't enforce this, so it's the type author's responsibility to implement __copyinit__() with value semantics. For example, here's a new HeapArray type that performs a deep copy in the copy constructor:\n\nstruct HeapArray:\n var data: UnsafePointer[Int]\n var size: Int\n var cap: Int\n\n fn __init__(inout self, size: Int, val: Int):\n self.size = size\n self.cap = size * 2\n self.data = UnsafePointer[Int].alloc(self.cap)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(val)\n\n fn __copyinit__(inout self, existing: Self):\n # Deep-copy the existing value\n self.size = existing.size\n self.cap = existing.cap\n self.data = UnsafePointer[Int].alloc(self.cap)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(existing.data[i])\n # The lifetime of `existing` continues unchanged\n\n fn __del__(owned self):\n # We must free the heap-allocated data, but\n # Mojo knows how to destroy the other fields\n for i in range(self.size):\n (self.data + i).destroy_pointee()\n self.data.free()\n\n fn append(inout self, val: Int):\n # Update the array for demo purposes\n if self.size < self.cap:\n (self.data + self.size).init_pointee_copy(val)\n self.size += 1\n else:\n print('Out of bounds')\n\n fn dump(self):\n # Print the array contents for demo purposes\n print('[', end='')\n for i in range(self.size):\n if i > 0:\n print(', ', end='')\n print(self.data[i], end='')\n print(']')\n\nNotice that __copyinit__() does not copy the UnsafePointer value (doing so would make the copied value refer to the same data memory address as the original value, which is a shallow copy). Instead, we initialize a new UnsafePointer to allocate a new block of memory, and then copy over all the heap-allocated values (this is a deep copy).\n\nThus, when we copy an instance of HeapArray, each copy has its own value on the heap, so changes to one value do not affect the other, as shown here:\n\nfn copies():\n var a = HeapArray(2, 1)\n var b = a # Calls the copy constructor\n a.dump() # Prints [1, 1]\n b.dump() # Prints [1, 1]\n\n b.append(2) # Changes the copied data\n b.dump() # Prints [1, 1, 2]\n a.dump() # Prints [1, 1] (the original did not change)\n\nnote\n\nIn HeapArray, we must use the __del__() destructor to free the heap-allocated data when the HeapArray lifetime ends, but Mojo automatically destroys all other fields when their respective lifetimes end. We'll discuss this destructor more in Death of a value.\n\nIf your type doesn't use any pointers for heap-allocated data, then writing the constructor and copy constructor is all boilerplate code that you shouldn't have to write. For most structs that don't manage memory explicitly, you can just add the @value decorator to your struct definition and Mojo will synthesize the __init__(), __copyinit__(), and __moveinit__() methods.\n\nnote\n\nMojo also calls upon the copy constructor when a value is passed to a function that takes the argument as owned and when the lifetime of the given value does not end at that point. If the lifetime of the value does end there (usually indicated with the transfer sigil ^), then Mojo instead invokes the move constructor.\n\nMove constructor\n\nAlthough copying values provides predictable behavior that matches Mojo's value semantics, copying some data types can be a significant hit on performance. If you're familiar with reference semantics, then the solution here might seem clear: instead of making a copy when passing a value, share the value as a reference. And if the original variable is no longer needed, nullify the original to avoid any double-free or use-after-free errors. That's generally known as a move operation: the memory block holding the data remains the same (the memory does not actually move), but the pointer to that memory moves to a new variable.\n\nTo support moving a value, implement the __moveinit__() method. The __moveinit__() method performs a consuming move: it transfers ownership of a value from one variable to another when the original variable's lifetime ends (also called a 'destructive move').\n\nnote\n\nA move constructor is not required to transfer ownership of a value. Unlike in Rust, transferring ownership is not always a move operation; the move constructors are only part of the implementation for how Mojo transfers ownership of a value. You can learn more in the section about ownership transfer.\n\nWhen a move occurs, Mojo immediately invalidates the original variable, preventing any access to it and disabling its destructor. Invalidating the original variable is important to avoid memory errors on heap-allocated data, such as use-after-free and double-free errors.\n\nHere's how to add the move constructor to the HeapArray example:\n\nstruct HeapArray:\n var data: UnsafePointer[Int]\n var size: Int\n var cap: Int\n\n\n fn __init__(inout self, size: Int, val: Int):\n self.size = size\n self.cap = size * 2\n self.data = UnsafePointer[Int].alloc(self.size)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(val)\n\n fn __copyinit__(inout self, existing: Self):\n # Deep-copy the existing value\n self.size = existing.size\n self.cap = existing.cap\n self.data = UnsafePointer[Int].alloc(self.cap)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(existing.data[i])\n # The lifetime of `existing` continues unchanged\n\n fn __moveinit__(inout self, owned existing: Self):\n print('move')\n # Shallow copy the existing value\n self.size = existing.size\n self.cap = existing.cap\n self.data = existing.data\n # Then the lifetime of `existing` ends here, but\n # Mojo does NOT call its destructor\n\n fn __del__(owned self):\n # We must free the heap-allocated data, but\n # Mojo knows how to destroy the other fields\n for i in range(self.size):\n (self.data + i).destroy_pointee()\n self.data.free()\n\n fn append(inout self, val: Int):\n # Update the array for demo purposes\n if self.size < self cap:\n (self.data + self.size).init_pointee_copy(val)\n self.size += 1\n else:\n print('Out of bounds')\n\n fn dump(self):\n # Print the array contents for demo purposes\n print('[', end='')\n for i in range(self.size):\n if i > 0:\n print(', ', end='')\n print(self.data[i], end='')\n print(']')\n\nThe critical feature of __moveinit__() is that it takes the incoming value as owned, meaning this method gets unique ownership of the value. Moreover, because this is a dunder method that Mojo calls only when performing a move (during ownership transfer), the existing argument is guaranteed to be a mutable reference to the original value, not a copy (unlike other methods that may declare an argument as owned, but might receive the value as a copy if the method is called without the ^ transfer sigil). That is, Mojo calls this move constructor only when the original variable's lifetime actually ends at the point of transfer.\n\nHere's an example showing how to invoke the move constructor for HeapArray:\n\nfn moves():\n var a = HeapArray(3, 1)\n\n a.dump() # Prints [1, 1, 1]\n\n var b = a^ # Prints 'move'; the lifetime of `a` ends here\n\n b.dump() # Prints [1, 1, 1]\n #a.dump() # ERROR: use of uninitialized value 'a'\n\nNotice that __moveinit__() performs a shallow copy of the existing field values (it copies the pointer, instead of allocating new memory on the heap), which is what makes it useful for types with heap-allocated values that are expensive to copy.\n\nTo go further and ensure your type can never be copied, you can make it 'move-only' by implementing __moveinit__() and excluding __copyinit__(). A move-only type can be passed to other variables and passed into functions with any argument convention (borrowed, inout, and owned)—the only catch is that you must use the ^ transfer sigil to end the lifetime of a move-only type when assigning it to a new variable or when passing it as an owned argument.\n\nnote\n\nFor types without heap-allocated fields, you get no real benefit from the move constructor. Making copies of simple data types on the stack, like integers, floats, and booleans, is very cheap. Yet, if you allow your type to be copied, then there's generally no reason to disallow moves, so you can synthesize both constructors by adding the @value decorator.\n\nSimple value types\n\nBecause copy and move constructors are opt-in, Mojo provides great control for exotic use cases (such as for atomic values that should never be copied or moved), but most structs are simple aggregations of other types that should be easily copied and moved, and we don't want to write a lot of boilerplate constructors for those simple value types.\n\nTo solve this, Mojo provides the @value decorator, which synthesizes the boilerplate code for the __init__(), __copyinit__(), and __moveinit__() methods.\n\nFor example, consider a simple struct like this:\n\n@value\nstruct MyPet:\n var name: String\n var age: Int\n\nMojo sees the @value decorator and notices that you don't have a member-wise initializer (a constructor with arguments for each field), a copy constructor, or a move constructor, so it synthesizes them for you. The result is as if you had actually written this:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, owned name: String, age: Int):\n self.name = name^\n self.age = age\n\n fn __copyinit__(inout self, existing: Self):\n self.name = existing.name\n self.age = existing.age\n\n fn __moveinit__(inout self, owned existing: Self):\n self.name = existing.name^\n self.age = existing.age\n\nMojo synthesizes each lifecycle method only when it doesn't exist, so you can use @value and still define your own versions to override the default behavior. For example, it is fairly common to use the default member-wise and move constructor, but create a custom copy constructor. Another common pattern is to use @value to create a member-wise constructor, and add overloads that take different sets of arguments. For example, if you want to create a MyPet struct without specifying an age, you could add an overloaded constructor:\n\n@value\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, owned name: String):\n self.name = name^\n self.age = 0\n\nNote that this overloaded constructor doesn't prevent the @value decorator from synthesizing the member-wise constructor. To override this default constructor, you'd need to add a constructor with the same signature as the default member-wise constructor.\n\nSomething you can see in this code that we didn't mention yet is that the __init__() method takes all arguments as owned, because the constructor must take ownership to store each value. This is a useful micro-optimization and enables the use of move-only types. Trivial types like Int are also passed as owned, but because ownership doesn't mean anything for integers, we can elide that declaration and the transfer sigil (^) for simplicity. The transfer operator is also just a formality in this case, because, even if it's not used with self.name = name^, the Mojo compiler will notice that name is last used here and convert this assignment into a move, instead of a copy+delete.\n\nnote\n\nIf your type contains any move-only fields, Mojo will not generate the copy constructor because it cannot copy those fields. Further, the @value decorator won't work at all if any of your members are neither copyable nor movable. For example, if you have something like Atomic in your struct, then it probably isn't a true value type, and you don't want the copy/move constructors anyway.\n\nAlso notice that the MyPet struct above doesn't include the __del__() destructor (the @value decorator does not synthesize this), because Mojo doesn't need it to destroy fields, as discussed in Death of a value\n\nTrivial types\n\nSo far, we've talked about values that live in memory, which means they have an identity (an address) that can be passed around among functions (passed 'by reference'). This is great for most types, and it's a safe default for large objects with expensive copy operations. However, it's inefficient for tiny things like a single integer or floating point number. We call these types 'trivial' because they are just 'bags of bits' that should be copied, moved, and destroyed without invoking any custom lifecycle methods.\n\nTrivial types are the most common types that surround us, and from a language perspective, Mojo doesn’t need special support for these written in a struct. Usually, these values are so tiny that they should be passed around in CPU registers, not indirectly through memory.\n\nAs such, Mojo provides a struct decorator to declare these types of values: @register_passable('trivial'). This decorator tells Mojo that the type should be copyable and movable but that it has no user-defined logic (no lifecycle methods) for doing this. It also tells Mojo to pass the value in CPU registers whenever possible, which has clear performance benefits.\n\nYou'll see this decorator on types like Int in the standard library:\n\n@register_passable('trivial')\nstruct Int:\n var value: __mlir_type.index\n\n fn __init__(value: __mlir_type.index) -> Int:\n return Self {value: value}\n ...\n\nWe expect to use this decorator pervasively on Mojo standard library types, but it is safe to ignore for general application-level code.\n\nFor more information, see the @register_passable documentation.\n\nTODO\n\nThis decorator is due for reconsideration. Lack of custom copy/move/destroy logic and 'passability in a register' are orthogonal concerns and should be split. This former logic should be subsumed into a more general @value('trivial') decorator, which is orthogonal from @register_passable.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/lifecycle/life",
"description": "Life of a Value in Mojo"
}
]
},
{
"document_id": "3",
"metadata": {
"title": "Death of a Value",
"description": "A deeper dive into the death of a value in Mojo",
"page_count": 1
},
"content":"Death of a value\n\nAs soon as a value/object is no longer used, Mojo destroys it. Mojo does not wait until the end of a code block—or even until the end of an expression—to destroy an unused value. It destroys values using an “as soon as possible” (ASAP) destruction policy that runs after every sub-expression. Even within an expression like a+b+c+d, Mojo destroys the intermediate values as soon as they're no longer needed.\n\nMojo uses static compiler analysis to find the point where a value is last used. Then, Mojo immediately ends the value's lifetime and calls the __del__() destructor to perform any necessary cleanup for the type.\n\nFor example, notice when the __del__() destructor is called for each instance of MyPet:\n\n@value\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __del__(owned self):\n print(\"Destruct\", self.name)\n\nfn pets():\n var a = MyPet(\"Loki\", 4)\n var b = MyPet(\"Sylvie\", 2)\n print(a.name)\n # a.__del__() runs here for \"Loki\"\n\n a = MyPet(\"Charlie\", 8)\n # a.__del__() runs immediately because \"Charlie\" is never used\n\n print(b.name)\n # b.__del__() runs here\n\npets()\n\nLoki\nDestruct Loki\nDestruct Charlie\nSylvie\nDestruct Sylvie\n\nNotice that each initialization of a value is matched with a call to the destructor, and a is actually destroyed multiple times—once for each time it receives a new value.\n\nAlso notice that this __del__() implementation doesn't actually do anything. Most structs don't require a custom destructor, and Mojo automatically adds a no-op destructor if you don't define one.\nDefault destruction behavior\n\nYou may be wondering how Mojo can destroy a type without a custom destructor, or why a no-op destructor is useful. If a type is simply a collection of fields, like the MyPet example, Mojo only needs to destroy the fields: MyPet doesn't dynamically allocate memory or use any long-lived resources (like file handles). There's no special action to take when a MyPet value is destroyed.\n\nLooking at the individual fields, MyPet includes an Int and a String. The Int is what Mojo calls a trivial type. It's a statically-sized bundle of bits. Mojo knows exactly how big it is, so those bits can be reused to store something else.\n\nThe String value is a little more complicated. Mojo strings are mutable. The String object has an internal buffer—a List field, which holds the characters that make up the string. A List stores its contents in dynamically allocated memory on the heap, so the string can grow or shrink. The string itself doesn't have any special destructor logic, but when Mojo destroys a string, it calls the destructor for the List field, which de-allocates the memory.\n\nSince String and Int don't require any custom destructor logic, they both have no-op destructors: literally, __del__() methods that don't do anything. This may seem pointless, but it means that Mojo can call the destructor on any value when its lifetime ends. This makes it easier to write generic containers and algorithms.\nBenefits of ASAP destruction\n\nSimilar to other languages, Mojo follows the principle that objects/values acquire resources in a constructor (__init__()) and release resources in a destructor (__del__()). However, Mojo's ASAP destruction has some advantages over scope-based destruction (such as the C++ RAII pattern, which waits until the end of the code scope to destroy values):\n\n Destroying values immediately at last-use composes nicely with the \"move\" optimization, which transforms a \"copy+del\" pair into a \"move\" operation.\n\n Destroying values at end-of-scope in C++ is problematic for some common patterns like tail recursion, because the destructor call happens after the tail call. This can be a significant performance and memory problem for certain functional programming patterns, which is not a problem in Mojo, because the destructor call always happens before the tail call.\n\nAdditionally, Mojo's ASAP destruction works great within Python-style def functions. That's because Python doesn’t really provide scopes beyond a function scope, so the Python garbage collector cleans up resources more often than a scope-based destruction policy would. However, Mojo does not use a garbage collector, so the ASAP destruction policy provides destruction guarantees that are even more fine-grained than in Python.\n\nThe Mojo destruction policy is more similar to how Rust and Swift work, because they both have strong value ownership tracking and provide memory safety. One difference is that Rust and Swift require the use of a dynamic \"drop flag\"—they maintain hidden shadow variables to keep track of the state of your values to provide safety. These are often optimized away, but the Mojo approach eliminates this overhead entirely, making the generated code faster and avoiding ambiguity.\nDestructor\n\nMojo calls a value's destructor (__del__() method) when the value's lifetime ends (typically the point at which the value is last used). As we mentioned earlier, Mojo provides a default, no-op destructor for all types, so in most cases you don't need to define the __del__() method.\n\nYou should define the __del__() method to perform any kind of cleanup the type requires. Usually, that includes freeing memory for any fields where you dynamically allocated memory (for example, via UnsafePointer) and closing any long-lived resources such as file handles.\n\nHowever, any struct that is just a simple collection of other types does not need to implement the destructor.\n\nFor example, consider this simple struct:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, name: String, age: Int):\n self.name = name\n self.age = age\n\nThere's no need to define the __del__() destructor for this, because it's a simple collection of other types (String and Int), and it doesn't dynamically allocate memory.\n\nWhereas, the following struct must define the __del__() method to free the memory allocated by its UnsafePointer:\n\nfrom memory.unsafe_pointer import UnsafePointer\n\nstruct HeapArray:\n var data: UnsafePointer[Int]\n var size: Int\n\n fn __init__(inout self, size: Int, val: Int):\n self.size = size\n self.data = UnsafePointer[Int].alloc(self.size)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(val)\n\n fn __del__(owned self):\n for i in range(self.size):\n (self.data + i).destroy_pointee()\n self.data.free()\n\nNote that a pointer doesn't own any values in the memory it points to, so when a pointer is destroyed, Mojo doesn't call the destructors on those values.\n\nSo in the HeapArray example above, calling free() on the pointer releases the memory, but doesn't call the destructors on the stored values. To invoke the destructors, use the destroy_pointee() method provided by the UnsafePointer type.\nnote\n\nYou can't just call the destructor explicitly. Because __del__() takes self as an owned value, and owned arguments are copied by default, foo.__del__() actually creates and destroys a copy of foo. When Mojo destroys a value, however, it passes in the original value as self, not a copy.\n\nIt's important to notice that the __del__() method is an \"extra\" cleanup event, and your implementation does not override any default destruction behaviors. For example, Mojo still destroys all the fields in MyPet even if you implement __del__() to do nothing:\n\nstruct MyPet:\n var name: String\n var age: Int\n\n fn __init__(inout self, name: String, age: Int):\n self.name = name\n self.age = age\n\n fn __del__(owned self):\n # Mojo destroys all the fields when they're last used\n pass\n\nHowever, the self value inside the __del__() destructor is still whole (so all fields are still usable) until the destructor returns, as we'll discuss more in the following section.\nField lifetimes\n\nIn addition to tracking the lifetime of all objects in a program, Mojo also tracks each field of a structure independently. That is, Mojo keeps track of whether a \"whole object\" is fully or partially initialized/destroyed, and it destroys each field independently with its ASAP destruction policy.\n\nFor example, consider this code that changes the value of a field:\n\n@value\nstruct MyPet:\n var name: String\n var age: Int\n\nfn use_two_strings():\n var pet = MyPet(\"Po\", 8)\n print(pet.name)\n # pet.name.__del__() runs here, because this instance is\n # no longer used; it's replaced below\n\n pet.name = String(\"Lola\") # Overwrite pet.name\n print(pet.name)\n # pet.__del__() runs here\n\nThe pet.name field is destroyed after the first print(), because Mojo knows that it will be overwritten below. You can also see this behavior when using the transfer sigil:\n\nfn consume(owned arg: String):\n pass\n\nfn use(arg: MyPet):\n print(arg.name)\n\nfn consume_and_use():\n var pet = MyPet(\"Selma\", 5)\n consume(pet.name^)\n # pet.name.__moveinit__() runs here, which destroys pet.name\n # Now pet is only partially initialized\n\n # use(pet) # This fails because pet.name is uninitialized\n\n pet.name = String(\"Jasper\") # All together now\n use(pet) # This is ok\n # pet.__del__() runs here (and only if the object is whole)\n\nNotice that the code transfers ownership of the name field to consume(). For a period of time after that, the name field is uninitialized. Then name is reinitialized before it is passed to the use() function. If you try calling use() before name is re-initialized, Mojo rejects the code with an uninitialized field error.\n\nAlso, if you don't re-initialize the name by the end of the pet lifetime, the compiler complains because it's unable to destroy a partially initialized object.\n\nMojo's policy here is powerful and intentionally straight-forward: fields can be temporarily transferred, but the \"whole object\" must be constructed with the aggregate type’s initializer and destroyed with the aggregate destructor. This means it's impossible to create an object by initializing only its fields, and it's likewise impossible to destroy an object by destroying only its fields.\nField lifetimes during destruct and move\n\nThe consuming-move constructor and destructor face an interesting situation with field lifetimes, because, unlike other lifecycle methods, they both take an instance of their own type as an owned argument, which is about to be destroyed. You don't really need to worry about this detail when implementing these methods, but it might help you better understand field lifetimes.\n\nJust to recap, the move constructor and destructor method signatures look like this:\n\nstruct TwoStrings:\n fn __moveinit__(inout self, owned existing: Self):\n # Initializes a new `self` by consuming the contents of `existing`\n fn __del__(owned self):\n # Destroys all resources in `self`\n\nnote\n\nThere are two kinds of \"self\" here: capitalized Self is an alias for the current type name (used as a type specifier for the existing argument), whereas lowercase self is the argument name for the implicitly-passed reference to the current instance (also called \"this\" in other languages, and also implicitly a Self type).\n\nBoth of these methods face an interesting but obscure problem: they both must dismantle the existing/self value that's owned. That is, __moveinit__() implicitly destroys sub-elements of existing in order to transfer ownership to a new instance (read more about the move constructor), while __del__() implements the deletion logic for its self. As such, they both need to own and transform elements of the owned value, and they definitely don’t want the original owned value's destructor to also run—that could result in a double-free error, and in the case of the __del__() method, it would become an infinite loop.\n\nTo solve this problem, Mojo handles these two methods specially by assuming that their whole values are destroyed upon reaching any return from the method. This means that the whole object may be used as usual, up until the field values are transferred or the method returns.\n\nFor example, the following code works as you would expect (within the destructor, we can still pass ownership of a field value to another function, and there's no infinite loop to destroy self):\n\nfn consume(owned str: String):\n print('Consumed', str)\n\nstruct TwoStrings:\n var str1: String\n var str2: String\n\n fn __init__(inout self, one: String):\n self.str1 = one\n self.str2 = String(\"bar\")\n\n fn __moveinit__(inout self, owned existing: Self):\n self.str1 = existing.str1\n self.str2 = existing.str2\n\n fn __del__(owned self):\n self.dump() # Self is still whole here\n # Mojo calls self.str2.__del__() since str2 isn't used anymore\n\n consume(self.str1^)\n # self.str1 has been transferred so it is also destroyed now;\n # `self.__del__()` is not called (avoiding an infinite loop).\n\n fn dump(inout self):\n print('str1:', self.str1)\n print('str2:', self.str2)\n\nfn use_two_strings():\n var two_strings = TwoStrings(\"foo\")\n\nExplicit lifetimes\n\nSo far, we've described how Mojo destroys a value at the point it's last used, and this works great in almost all situations. However, there are very rare situations in which Mojo simply cannot predict this correctly and will destroy a value that is still referenced through some other means.\n\nFor instance, perhaps you're building a type with a field that carries a pointer to another field. The Mojo compiler won't be able to reason about the pointer, so it might destroy a field (obj1) when that field is technically no longer used, even though another field (obj2) still holds a pointer to part of it. So, you might need to keep obj1 alive until you can execute some special logic in the destructor or move initializer.\n\nYou can force Mojo to keep a value alive up to a certain point by assigning the value to the _ discard pattern at the point where it's okay to destroy it. For example:\n\nfn __del__(owned self):\n self.dump() # Self is still whole here\n\n consume(self.obj2^)\n _ = self.obj1\n # Mojo keeps `obj1` alive until here, after its \"last use\"\n\nIn this case, if consume() refers to some value in obj1 somehow, this ensures that Mojo does not destroy obj1 until after the call to consume(), because assignment to the discard variable _ is actually the last use.\n\nFor other situations, you can also scope the lifetime of a value using the Python-style with statement. That is, for any value defined at the entrance to a with statement, Mojo will keep that value alive until the end of the with statement. For example:\n\nwith open(\"my_file.txt\", \"r\") as file:\n print(file.read())\n\n # Other stuff happens here (whether using `file` or not)...\n foo()\n # `file` is alive up to the end of the `with` statement.\n\n# `file` is destroyed when the statement ends.\nbar()",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/lifecycle/death",
"description": "Death of a Value in Mojo"
}
]
}
]
},
{
"section": "Traits and Parameters",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Mojo Traits",
"description": "An introduction to Mojo Traits",
"page_count": 1
},
"content":"Traits\n\nA trait is a set of requirements that a type must implement. You can think of it as a contract: a type that conforms to a trait guarantees that it implements all of the features of the trait.\n\nTraits are similar to Java interfaces, C++ concepts, Swift protocols, and Rust traits. If you're familiar with any of those features, Mojo traits solve the same basic problem.\n\nBackground\n\nIn dynamically-typed languages like Python, you don't need to explicitly declare that two classes are similar. This is easiest to show by example:\n\n%%python\nclass Duck:\n def quack(self):\n print(\"Quack.\")\n\nclass StealthCow:\n def quack(self):\n print(\"Moo!\")\n\ndef make_it_quack_python(maybe_a_duck):\n try:\n maybe_a_duck.quack()\n except:\n print(\"Not a duck.\")\n\nmake_it_quack_python(Duck())\nmake_it_quack_python(StealthCow())\n\nThe Duck and StealthCow classes aren't related in any way, but they both define a quack() method, so they work the same in the make_it_quack() function. This works because Python uses dynamic dispatch—it identifies the methods to call at runtime. So make_it_quack_python() doesn't care what types you're passing it, only the fact that they implement the quack() method.\n\nIn a statically-typed environment, this approach doesn't work: fn functions require you to specify the type of each argument. If you wanted to write this example in Mojo without traits, you'd need to write a function overload for each input type. All of the examples from here on are in Mojo, so we'll just call the function make_it_quack() going forward.\n\n@value\nstruct Duck:\n fn quack(self):\n print(\"Quack\")\n\n@value\nstruct StealthCow:\n fn quack(self):\n print(\"Moo!\")\n\nfn make_it_quack(definitely_a_duck: Duck):\n definitely_a_duck.quack()\n\nfn make_it_quack(not_a_duck: StealthCow):\n not_a_duck.quack()\n\nmake_it_quack(Duck())\nmake_it_quack(StealthCow())\n\nQuack\nMoo!\n\nThis isn't too bad with only two classes. But the more classes you want to support, the less practical this approach is.\n\nYou might notice that the Mojo versions of make_it_quack() don't include the try/except statement. We don't need it because Mojo's static type checking ensures that you can only pass instances of Duck or StealthCow into the make_it_quack()function.\n\nUsing traits\n\nTraits solve this problem by letting you define a shared set of behaviors that types can implement. Then you can write a function that depends on the trait, rather than individual types. As an example, let's update the make_it_quack() example using traits. The first step is defining a trait:\n\ntrait Quackable:\n fn quack(self):\n ...\n\nA trait looks a lot like a struct, except it's introduced by the trait keyword. Right now, a trait can only contain method signatures, and cannot include method implementations. Each method signature must be followed by three dots (...) to indicate that the method is unimplemented.\n\nTODO\n\nIn the future, we plan to support defining fields and default method implementations inside a trait. Right now, though, a trait can only declare method signatures.\n\nNext we create some structs that conform to the Quackable trait. To indicate that a struct conforms to a trait, include the trait name in parenthesis after the struct name. You can also include multiple traits, separated by commas. (If you're familiar with Python, this looks just like Python's inheritance syntax.)\n\n@value\nstruct Duck(Quackable):\n fn quack(self):\n print(\"Quack\")\n\n@value\nstruct StealthCow(Quackable):\n fn quack(self):\n print(\"Moo!\")\n\nThe struct needs to implement any methods that are declared in the trait. The compiler enforces conformance: if a struct says it conforms to a trait, it must implement everything required by the trait or the code won't compile.\n\nFinally, you can define a function that takes a Quackable like this:\n\nfn make_it_quack[T: Quackable](maybe_a_duck: T):\n maybe_a_duck.quack()\n\nThis syntax may look a little unfamiliar if you haven't dealt with Mojo parameters before. What this signature means is that maybe_a_duck is an argument of type T, where T is a type that must conform to the Quackable trait. TODO: This syntax is a little verbose, and we hope to make it more ergonomic in a future release.\n\nUsing the method is simple enough:\n\nmake_it_quack(Duck())\nmake_it_quack(StealthCow())\n\nQuack\nMoo!\n\nNote that you don't need the square brackets when you call make_it_quack(): the compiler infers the type of the argument, and ensures the type has the required trait.\n\nOne limitation of traits is that you can't add traits to existing types. For example, if you define a new Numeric trait, you can't add it to the standard library Float64 and Int types. However, the standard library already includes a few traits, and we'll be adding more over time.\n\nTraits can require static methods\n\nIn addition to regular instance methods, traits can specify required static methods.\n\ntrait HasStaticMethod:\n @staticmethod\n fn do_stuff(): ...\n\nfn fun_with_traits[T: HasStaticMethod]():\n T.do_stuff()\n\nImplicit trait conformance\n\nMojo also supports implicit trait conformance. That is, if a type implements all of the methods required for a trait, it's treated as conforming to the trait, even if it doesn't explicitly include the trait in its declaration:\n\nstruct RubberDucky:\n fn quack(self):\n print(\"Squeak!\")\n\nmake_it_quack(RubberDucky())\n\nImplicit conformance can be handy if you're defining a trait and you want it to work with types that you don't control—such as types from the standard library, or a third-party library.\n\nHowever, we still strongly recommend explicit trait conformance wherever possible. This has two advantages:\n\n Documentation. It makes it clear that the type conforms to the trait, without having to scan all of its methods.\n\n Future feature support. When default method implementations are added to traits, they'll only work for types that explicitly conform to traits.\n\nTrait inheritance\n\nTraits can inherit from other traits. A trait that inherits from another trait includes all of the requirements declared by the parent trait. For example:\n\ntrait Animal:\n fn make_sound(self):\n ...\n\n# Bird inherits from Animal\ntrait Bird(Animal):\n fn fly(self):\n ...\n\nSince Bird inherits from Animal, a struct that conforms to the Bird trait needs to implement both make_sound() and fly(). And since every Bird conforms to Animal, a struct that conforms to Bird can be passed to any function that requires an Animal.\n\nTo inherit from multiple traits, add a comma-separated list of traits inside the parenthesis. For example, you could define a NamedAnimal trait that combines the requirements of the Animal trait and a new Named trait:\n\ntrait Named:\n fn get_name(self) -> String:\n ...\n\ntrait NamedAnimal(Animal, Named):\n pass\n\nTraits and lifecycle methods\n\nTraits can specify required lifecycle methods, including constructors, copy constructors and move constructors.\n\nFor example, the following code creates a MassProducible trait. A MassProducible type has a default (no-argument) constructor and can be moved. It uses the built-in Movable trait, which requires the type to have a move constructor.\n\nThe factory[]() function returns a newly-constructed instance of a MassProducible type.\n\ntrait DefaultConstructible:\n fn __init__(inout self): ...\n\ntrait MassProducible(DefaultConstructible, Movable):\n pass\n\nfn factory[T: MassProducible]() -> T:\n return T()\n\nstruct Thing(MassProducible):\n var id: Int\n\n fn __init__(inout self):\n self.id = 0\n\n fn __moveinit__(inout self, owned existing: Self):\n self.id = existing.id\n\nvar thing = factory[Thing]()\n\nNote that @register_passable(\"trivial\") types have restrictions on their lifecycle methods: they can't define copy or move constructors, because they don't require any custom logic.\n\nFor the purpose of trait conformance, the compiler treats trivial types as copyable and movable.\n\nBuilt-in traits\nThe Mojo standard library currently includes a few traits. They're implemented by a number of standard library types, and you can also implement these on your own types:\n\nAbsable\n\nThe Absable trait describes a type that defines an absolute value operation.\n\nTypes that conform to Absable will work with the builtin abs function. The absolute value operation always returns the same type as the input.\n\nFor example:\n\nstruct Point(Absable):\n var x: Float64\n var y: Float64\n\n fn __abs__(self) -> Self:\n return sqrt(self.x * self.x + self.y * self.y)\n\nImplemented traits\n\nAnyType\nMethods\n__abs__\n\n__abs__(self: T) -> T\n\nGet the absolute value of this instance.\n\nReturns:\n\nThe absolute value of the instance.\n\nAnyType\n\nThe AnyType trait describes a type that has a destructor.\n\nIn Mojo, a type that provide a destructor indicates to the language that it is an object with a lifetime whose destructor needs to be called whenever an instance of the object reaches the end of its lifetime. Hence, only non-trivial types may have destructors.\n\nAny composition of types that have lifetimes is also an object with a lifetime, and the resultant type receives a destructor regardless of whether the user explicitly defines one.\n\nAll types pessimistically require a destructor when used in generic functions. Hence, all Mojo traits are considered to inherit from AnyType, providing a default no-op destructor implementation for types that may need them.\n\nExample implementing the AnyType trait on Foo that frees the allocated memory:\n\n@value\nstruct Foo(AnyType):\n var p: UnsafePointer[Int]\n var size: Int\n\n fn __init__(inout self, size: Int):\n self.p = UnsafePointer[Int].alloc(size)\n self.size = size\n\n fn __del__(owned self):\n print(\"--freeing allocated memory--\")\n self.p.free()\n\nMethods\n__del__\n\n__del__(owned self: T, /)\n\nDestroy the contained value.\n\nThe destructor receives an owned value and is expected to perform any actions needed to end the lifetime of the object. In the simplest case, this is nothing, and the language treats the object as being dead at the end of this function.\n\nBoolable\n\nThe Boolable trait describes a type that can be explicitly converted to a Bool or evaluated as a boolean expression in if or while conditions.\n\nThis trait requires the type to implement the __bool__() method. For example:\n\n@value\nstruct Foo(Boolable):\n var val: Bool\n\n fn __bool__(self) -> Bool:\n return self.val\n\nImplemented traits\n\nAnyType\nMethods\n__bool__\n\n__bool__(self: T) -> Bool\n\nGet the boolean representation of the value.\n\nReturns:\n\nThe boolean representation of the value.\n\nBoolableCollectionElement\n\nThe BoolableCollectionElement trait denotes a trait composition of the Boolable and CollectionElement traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on Boolable & CollectionElement in the parameter.\nImplemented traits\n\nAnyType, Boolable, CollectionElement, Copyable, Movable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__bool__\n\n__bool__(self: T) -> Bool\n\nGet the boolean representation of the value.\n\nReturns:\n\nThe boolean representation of the value.\n\nBoolableKeyElement\n\nThe BoolableKeyElement trait denotes a trait composition of the Boolable and KeyElement traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on Boolable & KeyElement in the parameter.\nImplemented traits\n\nAnyType, Boolable, CollectionElement, Copyable, EqualityComparable, Hashable, KeyElement, Movable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__bool__\n\n__bool__(self: T) -> Bool\n\nGet the boolean representation of the value.\n\nReturns:\n\nThe boolean representation of the value.\n__eq__\n\n__eq__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are equal according to the type's definition of equality, False otherwise.\n__ne__\n\n__ne__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are not equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are not equal according to the type's definition of equality, False otherwise.\n__hash__\n\n__hash__(self: T) -> UInt\n\nReturn a 64-bit hash of the type's data.\n\nReturns:\n\nA 64-bit integer hash of this instance's data.\n\nCollectionElement\n\nThe CollectionElement trait denotes a trait composition of the Copyable and Movable traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on Copyable & Movable in the parameter.\nImplemented traits\n\nAnyType, Copyable, Movable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\nComparable\n\nA type which can be compared with other instances of itself.\nImplemented traits\n\nAnyType, EqualityComparable\nMethods\n__lt__\n\n__lt__(self: T, rhs: T) -> Bool\n\nDefine whether self is less than rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is less than rhs.\n__le__\n\n__le__(self: T, rhs: T) -> Bool\n\nDefine whether self is less than or equal to rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is less than or equal to rhs.\n__eq__\n\n__eq__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are equal according to the type's definition of equality, False otherwise.\n__ne__\n\n__ne__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are not equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are not equal according to the type's definition of equality, False otherwise.\n__gt__\n\n__gt__(self: T, rhs: T) -> Bool\n\nDefine whether self is greater than rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is greater than rhs.\n\nComparableCollectionElement\n\nThis trait denotes a trait composition of the CollectionElement and Comparable traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on CollectionElement & Comparable in the parameter.\nImplemented traits\n\nAnyType, CollectionElement, Comparable, Copyable, EqualityComparable, Movable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__lt__\n\n__lt__(self: T, rhs: T) -> Bool\n\nDefine whether self is less than rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is less than rhs.\n__le__\n\n__le__(self: T, rhs: T) -> Bool\n\nDefine whether self is less than or equal to rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is less than or equal to rhs.\n__eq__\n\n__eq__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are equal according to the type's definition of equality, False otherwise.\n__ne__\n\n__ne__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are not equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are not equal according to the type's definition of equality, False otherwise.\n__gt__\n\n__gt__(self: T, rhs: T) -> Bool\n\nDefine whether self is greater than rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is greater than rhs.\n__ge__\n\n__ge__(self: T, rhs: T) -> Bool\n\nDefine whether self is greater than or equal to rhs.\n\nArgs:\n\n rhs (T): The right hand side of the comparison.\n\nReturns:\n\nTrue if self is greater than or equal to rhs.\n\nCopyable\n\nThe Copyable trait denotes a type whose value can be copied.\n\nExample implementing the Copyable trait on Foo which requires the __copyinit__ method:\n\nstruct Foo(Copyable):\n var s: String\n\n fn __init__(inout self, s: String):\n self.s = s\n\n fn __copyinit__(inout self, other: Self):\n print(\"copying value\")\n self.s = other.s\n\nYou can now copy objects inside a generic function:\n\nfn copy_return[T: Copyable](foo: T) -> T:\n var copy = foo\n return copy\n\nvar foo = Foo(\"test\")\nvar res = copy_return(foo)\n\ncopying value\n\nImplemented traits\n\nAnyType\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\nDefaultable\n\nThe Defaultable trait describes a type with a default constructor.\n\nImplementing the Defaultable trait requires the type to define an __init__ method with no arguments:\n\nstruct Foo(Defaultable):\n var s: String\n\n fn __init__(inout self):\n self.s = \"default\"\n\nYou can now construct a generic Defaultable type:\n\nfn default_init[T: Defaultable]() -> T:\n return T()\n\nvar foo = default_init[Foo]()\nprint(foo.s)\n\ndefault\n\nImplemented traits\n\nAnyType\nMethods\n__init__\n\n__init__(inout self: T, /)\n\nCreate a default instance of the value.\n\nFormattable\n\nThe Formattable trait describes a type that can be converted to a stream of UTF-8 encoded data by writing to a formatter object.\n\nExamples:\n\nImplement Formattable and Stringable for a type:\n\nstruct Point(Stringable, Formattable):\n var x: Float64\n var y: Float64\n\n fn __str__(self) -> String:\n return String.format_sequence(self)\n\n fn format_to(self, inout writer: Formatter):\n writer.write(\"(\", self.x, \", \", self.y, \")\")\n\nImplemented traits\n\nAnyType\nMethods\nformat_to\n\nformat_to(self: T, inout writer: Formatter)\n\nFormats the string representation of this type to the provided formatter.\n\nArgs:\n\n writer (Formatter): The formatter to write to.\n\nHashable\n\nA trait for types which specify a function to hash their data.\n\nThis hash function will be used for applications like hash maps, and don't need to be cryptographically secure. A good hash function will hash similar / common types to different values, and in particular the low order bits of the hash, which are used in smaller dictionaries, should be sensitive to any changes in the data structure. If your type's hash function doesn't meet this criteria it will get poor performance in common hash map implementations.\n\n@value\nstruct Foo(Hashable):\n fn __hash__(self) -> UInt:\n return 4 # chosen by fair random dice roll\n\nvar foo = Foo()\nprint(hash(foo))\n\nImplemented traits\n\nAnyType\nMethods\n__hash__\n\n__hash__(self: T) -> UInt\n\nReturn a 64-bit hash of the type's data.\n\nReturns:\n\nA 64-bit integer hash of this instance's data.\n\nIndexer\n\nThis trait denotes a type that can be used to index a container that handles integral index values.\n\nThis solves the issue of being able to index data structures such as List with the various integral types without being too broad and allowing types that are coercible to Int (e.g. floating point values that have __int__ method). In contrast to Intable, types conforming to Indexer must be convertible to Int in a lossless way.\n\nNote that types conforming to Indexer are implicitly convertible to Int.\nImplemented traits\n\nAnyType\nMethods\n__index__\n\n__index__(self: T) -> Int\n\nReturn the index value.\n\nReturns:\n\nThe index value of the object.\n\nIntable\n\nThe Intable trait describes a type that can be converted to an Int.\n\nAny type that conforms to Intable or IntableRaising works with the built-in int() function.\n\nThis trait requires the type to implement the __int__() method. For example:\n\n@value\nstruct Foo(Intable):\n var i: Int\n\n fn __int__(self) -> Int:\n return self.i\n\nNow you can use the int() function to convert a Foo to an Int:\n\nvar foo = Foo(42)\nprint(int(foo) == 42)\n\nTrue\n\nIf the __int__() method can raise an error, use the IntableRaising trait instead.\nImplemented traits\n\nAnyType\nMethods\n__int__\n\n__int__(self: T) -> Int\n\nGet the integral representation of the value.\n\nReturns:\n\nThe integral representation of the value.\n\nIntableRaising\n\nThe IntableRaising trait describes a type can be converted to an Int, but the conversion might raise an error.\n\nAny type that conforms to Intable or IntableRaising works with the built-in int() function.\n\nThis trait requires the type to implement the __int__() method, which can raise an error. For example:\n\n@value\nstruct Foo(IntableRaising):\n var i: Int\n\n fn __int__(self) raises -> Int:\n return self.i\n\nNow you can use the int() function to convert a Foo to an Int:\n\nfn main() raises:\n var x = Foo(42)\n print(int(x) == 42)\n\nTrue\n\nImplemented traits\n\nAnyType\nMethods\n__int__\n\n__int__(self: T) -> Int\n\nGet the integral representation of the value.\n\nReturns:\n\nThe integral representation of the type.\n\nRaises:\n\nIf the type does not have an integral representation.\n\nKeyElement\n\nA trait composition for types which implement all requirements of dictionary keys. Dict keys must minimally be Movable, Hashable, and EqualityComparable for a hash map. Until we have references they must also be copyable.\nImplemented traits\n\nAnyType, CollectionElement, Copyable, EqualityComparable, Hashable, Movable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__eq__\n\n__eq__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are equal according to the type's definition of equality, False otherwise.\n__ne__\n\n__ne__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are not equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are not equal according to the type's definition of equality, False otherwise.\n__hash__\n\n__hash__(self: T) -> UInt\n\nReturn a 64-bit hash of the type's data.\n\nReturns:\n\nA 64-bit integer hash of this instance's data.\n\nMovable\n\nThe Movable trait denotes a type whose value can be moved.\n\nImplement the Movable trait on Foo which requires the __moveinit__ method:\n\nstruct Foo(Movable):\n fn __init__(inout self):\n pass\n\n fn __moveinit__(inout self, owned existing: Self):\n print(\"moving\")\n\nYou can now use the ^ suffix to move the object instead of copying it inside generic functions:\n\nfn return_foo[T: Movable](owned foo: T) -> T:\n return foo^\n\nvar foo = Foo()\nvar res = return_foo(foo^)\n\nmoving\n\nImplemented traits\n\nAnyType\nMethods\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\nPathLike\n\nA trait representing file system paths.\nImplemented traits\n\nAnyType\nMethods\n__fspath__\n\n__fspath__(self: T) -> String\n\nReturn the file system path representation of the object.\n\nReturns:\n\nThe file system path representation as a string.\n\nPowable\n\nThe Powable trait describes a type that defines a power operation (i.e. exponentiation) with the same base and exponent types.\n\nTypes that conform to Powable will work with the builtin pow function, which will return the same type as the inputs.\n\nFor example:\n\n@value\nstruct Rational(Powable):\n var numerator: Float64\n var denominator: Float64\n\n fn __init__(inout self, numerator: Float64, denominator: Float64):\n self.numerator = numerator\n self.denominator = denominator\n\n fn __pow__(self, exp: Self) -> Self:\n var exp_value = exp.numerator / exp.denominator\n return Self(pow(self.numerator, exp_value), pow(self.denominator, exp_value))\n\nYou can now use the ** operator to exponentiate objects inside generic functions:\n\nfn exponentiate[T: Powable](base: T, exp: T) -> T:\n return base ** exp\n\nvar base = Rational(Float64(3.0), 5.0)\nvar exp = Rational(Float64(1.0), 2.0)\nvar res = exponentiate(base, exp)\n\nraising to power\n\nImplemented traits\n\nAnyType\nMethods\n__pow__\n\n__pow__(self: T, exp: T) -> T\n\nReturn the value raised to the power of the given exponent.\n\nArgs:\n\n exp (T): The exponent value.\n\nReturns:\n\nThe value of self raised to the power of exp.\n\nRepresentable\n\nA trait that describes a type that has a String representation.\n\nAny type that conforms to the Representable trait can be used with the repr function. Any conforming type must also implement the __repr__ method. Here is an example:\n\n@value\nstruct Dog(Representable):\n var name: String\n var age: Int\n\n fn __repr__(self) -> String:\n return \"Dog(name=\" + repr(self.name) + \", age=\" + repr(self.age) + \")\"\n\nvar dog = Dog(\"Rex\", 5)\nprint(repr(dog))\n# Dog(name='Rex', age=5)\n\nThe method __repr__ should compute the \"official\" string representation of a type.\n\nIf at all possible, this should look like a valid Mojo expression that could be used to recreate a struct instance with the same value (given an appropriate environment). So a returned String of the form module_name.SomeStruct(arg1=value1, arg2=value2) is advised. If this is not possible, a string of the form <...some useful description...> should be returned.\n\nThe return value must be a String instance. This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.\n\nNote that when computing the string representation of a collection (Dict, List, Set, etc...), the repr function is called on each element, not the str() function.\nImplemented traits\n\nAnyType\nMethods\n__repr__\n\n__repr__(self: T) -> String\n\nGet the string representation of the type instance, if possible, compatible with Mojo syntax.\n\nReturns:\n\nThe string representation of the instance.\n\nRepresentableCollectionElement\n\nThe RepresentableCollectionElement trait denotes a trait composition of the CollectionElement and Representable traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on CollectionElement & Representable in the parameter.\nImplemented traits\n\nAnyType, CollectionElement, Copyable, Movable, Representable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__repr__\n\n__repr__(self: T) -> String\n\nGet the string representation of the type instance, if possible, compatible with Mojo syntax.\n\nReturns:\n\nThe string representation of the instance.\n\nRepresentableKeyElement\n\nA trait composition for types which implement all requirements of dictionary keys and Stringable.\nImplemented traits\n\nAnyType, CollectionElement, Copyable, EqualityComparable, Hashable, KeyElement, Movable, Representable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__eq__\n\n__eq__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are equal according to the type's definition of equality, False otherwise.\n__ne__\n\n__ne__(self: T, other: T) -> Bool\n\nDefine whether two instances of the object are not equal to each other.\n\nArgs:\n\n other (T): Another instance of the same type.\n\nReturns:\n\nTrue if the instances are not equal according to the type's definition of equality, False otherwise.\n__hash__\n\n__hash__(self: T) -> UInt\n\nReturn a 64-bit hash of the type's data.\n\nReturns:\n\nA 64-bit integer hash of this instance's data.\n__repr__\n\n__repr__(self: T) -> String\n\nGet the string representation of the type instance, if possible, compatible with Mojo syntax.\n\nReturns:\n\nThe string representation of the instance.\n\nSized\n\nThe Sized trait describes a type that has an integer length (such as a string or array).\n\nAny type that conforms to Sized or SizedRaising works with the built-in len() function.\n\nThe Sized trait requires a type to implement the __len__() method. For example:\n\n@value\nstruct Foo(Sized):\n var length: Int\n\n fn __len__(self) -> Int:\n return self.length\n\nYou can pass an instance of Foo to the len() function to get its length:\n\nvar foo = Foo(42)\nprint(len(foo) == 42)\n\nTrue\n\nIf the __len__() method can raise an error, use the SizedRaising trait instead.\nImplemented traits\n\nAnyType\nMethods\n__len__\n\n__len__(self: T) -> Int\n\nGet the length of the type.\n\nReturns:\n\nThe length of the type.\n\nStringable\n\nThe Stringable trait describes a type that can be converted to a String.\n\nAny type that conforms to Stringable or StringableRaising works with the built-in print() and str() functions.\n\nThe Stringable trait requires the type to define the __str__() method. For example:\n\n@value\nstruct Foo(Stringable):\n var s: String\n\n fn __str__(self) -> String:\n return self.s\n\nNow you can pass an instance of Foo to the str() function to get back a String:\n\nvar foo = Foo(\"test\")\nprint(str(foo) == \"test\")\n\nTrue\n\nIf the __str__() method might raise an error, use the StringableRaising trait, instead.\n\nAbout the difference between __repr__() and __str__(): The method __repr__ compute the compute the \"official\" string representation of an object while __str__ computes the \"informal\" or nicely printable string representation of an object.\n\nThis method differs from __repr__() in that there is no expectation that __str__() return a valid Mojo expression: a more convenient or concise representation can be used.\nImplemented traits\n\nAnyType\nMethods\n__str__\n\n__str__(self: T) -> String\n\nGet the string representation of the type.\n\nReturns:\n\nThe string representation of the type.\n\nStringableCollectionElement\n\nThe StringableCollectionElement trait denotes a trait composition of the CollectionElement and Stringable traits.\n\nThis is useful to have as a named entity since Mojo does not currently support anonymous trait compositions to constrain on CollectionElement & Stringable in the parameter.\nImplemented traits\n\nAnyType, CollectionElement, Copyable, Movable, Stringable\nMethods\n__copyinit__\n\n__copyinit__(inout self: T, existing: T, /)\n\nCreate a new instance of the value by copying an existing one.\n\nArgs:\n\n existing (T): The value to copy.\n\n__moveinit__\n\n__moveinit__(inout self: T, owned existing: T, /)\n\nCreate a new instance of the value by moving the value of another.\n\nArgs:\n\n existing (T): The value to move.\n\n__str__\n\n__str__(self: T) -> String\n\nGet the string representation of the type.\n\nReturns:\n\nThe string representation of the type.\n\nStringableRaising\n\nThe StringableRaising trait describes a type that can be converted to a String.\n\nAny type that conforms to Stringable or StringableRaising works with the built-in print() and str() functions.\n\nThe StringableRaising trait requires the type to define the __str__() method, which can raise an error. For example:\n\n@value\nstruct Foo(StringableRaising):\n var s: String\n\n fn __str__(self) raises -> String:\n if self.s == \"\":\n raise Error(\"Empty String\")\n return self.s\n\nNow you can pass an instance of Foo to the str() function to get back a String:\n\nfn main() raises:\n var foo = Foo(\"test\")\n print(str(foo) == \"test\")\n\nTrue\n\nImplemented traits\n\nAnyType\nMethods\n__str__\n\n__str__(self: T) -> String\n\nGet the string representation of the type.\n\nReturns:\n\nThe string representation of the type.\n\nRaises:\n\nIf there is an error when computing the string representation of the type.\n\nStringRepresentable\n\nThe StringRepresentable trait denotes a trait composition of the Stringable and Representable traits.\n\nThis trait is used by the format() method to support both {!s} (or {}) and {!r} format specifiers. It allows the method to handle types that can be formatted using both their string representation and their more detailed representation.\n\nTypes implementing this trait must provide both __str__() and __repr__() methods as defined in Stringable and Representable traits respectively.\nImplemented traits\n\nAnyType, Representable, Stringable\nMethods\n__str__\n\n__str__(self: T) -> String\n\nGet the string representation of the type.\n\nReturns:\n\nThe string representation of the type.\n__repr__\n\n__repr__(self: T) -> String\n\nGet the string representation of the type instance, if possible, compatible with Mojo syntax.\n\nReturns:\n\nThe string representation of the instance.\n\nRoundable\n\nThe Roundable trait describes a type that defines a rounding operation.\n\nTypes that conform to Roundable will work with the builtin round function. The round operation always returns the same type as the input.\n\nFor example:\n\n@value\nstruct Complex(Roundable):\n var re: Float64\n var im: Float64\n\n fn __round__(self) -> Self:\n return Self(round(re), round(im))\n\nImplemented traits\n\nAnyType\nMethods\n__round__\n\n__round__(self: T) -> T\n\nGet a rounded value for the type.\n\nReturns:\n\nThe rounded value.\n\n__round__(self: T, ndigits: Int) -> T\n\nGet a rounded value for the type.\n\nArgs:\n\n ndigits (Int): Number of digits after the decimal point.\n\nReturns:\n\nThe rounded value.\n\nThe Sized trait\n\nThe Sized trait identifies types that have a measurable length, like strings and arrays.\n\nSpecifically, Sized requires a type to implement the __len__() method. This trait is used by the built-in len() function. For example, if you're writing a custom list type, you could implement this trait so your type works with len():\n\nstruct MyList(Sized):\n var size: Int\n # ...\n\n fn __init__(inout self):\n self.size = 0\n\n fn __len__(self) -> Int:\n return self.size\n\nprint(len(MyList()))\n\n0\nThe Intable and IntableRaising traits\n\nThe Intable trait identifies a type that can be implicitly converted to Int. The IntableRaising trait describes a type can be converted to an Int, but the conversion might raise an error.\n\nBoth of these traits require the type to implement the __int__() method. For example:\n\n@value\nstruct Foo(Intable):\n var i: Int\n\n fn __int__(self) -> Int:\n return self.i\n\nvar foo = Foo(42)\nprint(int(foo) == 42)\n\nTrue\nThe Stringable, Representable, and Formattable traits\n\nThe Stringable trait identifies a type that can be implicitly converted to String. The StringableRaising trait describes a type that can be converted to a String, but the conversion might raise an error. Any type that conforms to Stringable or StringableRaising also works with the built-in str() function to explicitly return a String. These traits also mean that the type can support both the {!s} and {} format specifiers of the String class' format() method. These traits require the type to define the __str__() method.\n\nIn contrast, the Representable trait that defines a type that can be used with the built-in repr() function, as well as the {!r} format specifier of the format() method. This trait requires the type to define the __repr__() method, which should compute the \"official\" string representation of a type. If at all possible, this should look like a valid Mojo expression that could be used to recreate a struct instance with the same value.\n\nThe StringRepresentable trait denotes a trait composition of the Stringable and Representable traits. It requires a type to implement both a __str__() and a __repr__() method.\n\nThe Formattable trait describes a type that can be converted to a stream of UTF-8 encoded data by writing to a formatter object. The print() function requires that its arguments conform to the Formattable trait. This enables efficient stream-based writing by default, avoiding unnecessary intermediate String heap allocations.\n\nThe Formattable trait requires a type to implement a format_to() method, which is provided with an instance of Formatter as an argument. You then invoke the Formatter instance's write() method to write a sequence of Formattable arguments constituting the String representation of your type.\n\nWhile this might sound complex at first, in practice you can minimize boilerplate and duplicated code by using the String.format_sequence() static function to implement the type's Stringable implementation in terms of its Formattable implementation. Here is a simple example of a type that implements all of the Stringable, Representable, and Formattable traits:\n\n@value\nstruct Dog(Stringable, Representable, Formattable):\n var name: String\n var age: Int\n\n fn __repr__(self) -> String:\n return \"Dog(name=\" + repr(self.name) + \", age=\" + repr(self.age) + \")\"\n\n fn __str__(self) -> String:\n return String.format_sequence(self)\n\n fn format_to(self, inout writer: Formatter) -> None:\n writer.write(\"Dog(\", self.name, \", \", self.age, \")\")\n\nvar dog = Dog(\"Rex\", 5)\nprint(repr(dog))\nprint(dog)\n\nvar dog_info = String(\"String: {!s}\\nRepresentation: {!r}\").format(dog, dog)\nprint(dog_info)\n\nDog(name='Rex', age=5)\nDog(Rex, 5)\nString: Dog(Rex, 5)\nRepresentation: Dog(name='Rex', age=5)\nThe AnyType trait\n\nWhen building a generic container type, one challenge is knowing how to dispose of the contained items when the container is destroyed. Any type that dynamically allocates memory needs to supply a destructor (__del__() method) that must be called to free the allocated memory. But not all types have a destructor, and your Mojo code has no way to determine which is which.\n\nThe AnyType trait solves this issue: every trait implicitly inherits from AnyType, and all structs conform to AnyType, which guarantees that the type has a destructor. For types that don't have one, Mojo adds a no-op destructor. This means you can call the destructor on any type.\n\nThis makes it possible to build generic collections without leaking memory. When the collection's destructor is called, it can safely call the destructors on every item it contains.\nGeneric structs with traits\n\nYou can also use traits when defining a generic container. A generic container is a container (for example, an array or hashmap) that can hold different data types. In a dynamic language like Python it's easy to add different types of items to a container. But in a statically-typed environment the compiler needs to be able to identify the types at compile time. For example, if the container needs to copy a value, the compiler needs to verify that the type can be copied.\n\nThe List type is an example of a generic container. A single List can only hold a single type of data. For example, you can create a list of integer values like this:\n\nfrom collections import List\n\nvar list = List[Int](1, 2, 3)\nfor i in range(len(list)):\n print(list[i], sep=\" \", end=\"\")\n\n1 2 3\n\nYou can use traits to define requirements for elements that are stored in a container. For example, List requires elements that can be moved and copied. To store a struct in a List, the struct needs to conform to the CollectionElement trait, which requires a copy constructor and a move constructor.\n\nBuilding generic containers is an advanced topic. For an introduction, see the section on parameterized structs.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/traits",
"description": "Mojo Traits"
}
]
},
{
"document_id": "2",
"metadata": {
"title": "Parameterization: Metaprogramming",
"description": "How to use Parameterization for metaprogramming in Mojo",
"page_count": 1
},
"content": "Parameterization: compile-time metaprogramming\n\nMany languages have facilities for metaprogramming: that is, for writing code that generates or modifies code. Python has facilities for dynamic metaprogramming: features like decorators, metaclasses, and many more. These features make Python very flexible and productive, but since they're dynamic, they come with runtime overhead. Other languages have static or compile-time metaprogramming features, like C preprocessor macros and C++ templates. These can be limiting and hard to use.\n\nTo support Modular's work in AI, Mojo aims to provide powerful, easy-to-use metaprogramming with zero runtime cost. This compile-time metaprogramming uses the same language as runtime programs, so you don't have to learn a new language—just a few new features.\n\nThe main new feature is parameters. You can think of a parameter as a compile-time variable that becomes a runtime constant. This usage of \"parameter\" is probably different from what you're used to from other languages, where \"parameter\" and \"argument\" are often used interchangeably. In Mojo, \"parameter\" and \"parameter expression\" refer to compile-time values, and \"argument\" and \"expression\" refer to runtime values.\n\nIn Mojo, you can add parameters to a struct or function. You can also define named parameter expressions—aliases—that you can use as runtime constants.\nParameterized functions\n\nTo define a parameterized function, add parameters in square brackets ahead of the argument list. Each parameter is formatted just like an argument: a parameter name, followed by a colon and a type (which is required). In the following example, the function has a single parameter, count of type Int.\n\nfn repeat[count: Int](msg: String):\n @parameter\n for i in range(count):\n print(msg)\n\nThe @parameter directive shown here causes the for loop to be evaluated at compile time. The directive only works if the loop limits are compile-time constants. Since count is a parameter, range(count) can be calculated at compile time.\n\nCalling a parameterized function, you provide values for the parameters, just like function arguments:\n\nrepeat[3](\"Hello\")\n\nHello\nHello\nHello\n\nThe compiler resolves the parameter values during compilation, and creates a concrete version of the repeat[]() function for each unique parameter value. After resolving the parameter values and unrolling the loop, the repeat[3]() function would be roughly equivalent to this:\n\nfn repeat_3(msg: String):\n print(msg)\n print(msg)\n print(msg)\n\nnote\n\nThis doesn't represent actual code generated by the compiler. By the time parameters are resolved, Mojo code has already been transformed to an intermediate representation in MLIR.\n\nIf the compiler can't resolve all parameter values to constant values, compilation fails.\nParameters and generics\n\n\"Generics\" refers to functions that can act on multiple types of values, or containers that can hold multiple types of values. For example, List, can hold different types of values, so you can have a list of Int values, or a list of String values).\n\nIn Mojo, generics use parameters to specify types. For example, List takes a type parameter, so a vector of integers is written List[Int]. So all generics use parameters, but not everything that uses parameters is a generic.\n\nFor example, the repeat[]() function in the previous section includes parameter of type Int, and an argument of type String. It's parameterized, but not generic. A generic function or struct is parameterized on type. For example, we could rewrite repeat[]() to take any type of argument that conforms to the Stringable trait:\n\nfn repeat[MsgType: Stringable, count: Int](msg: MsgType):\n @parameter\n for i in range(count):\n print(str(msg))\n\n# Must use keyword parameter for `count`\nrepeat[count=2](42)\n\n42\n42\n\nThis updated function takes any Stringable type, so you can pass it an Int, String, or Bool value.\n\nYou can't pass the count as a positional keyword without also specifying MsgType. You can put // after MsgType to specify that it's always inferred by the argument. Now you can pass the following parameter count positionally:\n\nfn repeat[MsgType: Stringable, //, count: Int](msg: MsgType):\n @parameter\n for i in range(count):\n print(str(msg))\n\n# MsgType is always inferred, so first positional keyword `2` is passed to `count`\nrepeat[2](42)\n\n42\n42\n\nMojo's support for generics is still early. You can write generic functions like this using traits and parameters. You can also write generic collections like List and Dict. If you're interested in learning how these types work, you can find the source code for the standard library collection types on GitHub.\nParameterized structs\n\nYou can also add parameters to structs. You can use parameterized structs to build generic collections. For example, a generic array type might include code like this:\n\nfrom memory.unsafe_pointer import UnsafePointer\n\nstruct GenericArray[ElementType: CollectionElement]:\n var data: UnsafePointer[ElementType]\n var size: Int\n\n fn __init__(inout self, *elements: ElementType):\n self.size = len(elements)\n self.data = UnsafePointer[ElementType].alloc(self.size)\n for i in range(self.size):\n (self.data + i).init_pointee_move(elements[i])\n\n fn __del__(owned self):\n for i in range(self.size):\n (self.data + i).destroy_pointee()\n self.data.free()\n\n fn __getitem__(self, i: Int) raises -> ref [__lifetime_of(self)] ElementType:\n if (i < self.size):\n return self.data[i]\n else:\n raise Error(\"Out of bounds\")\n\nThis struct has a single parameter, ElementType, which is a placeholder for the data type you want to store in the array, sometimes called a type parameter. ElementType is typed as CollectionElement, which is a trait representing any type that can be copied and moved.\n\nAs with parameterized functions, you need to pass in parameter values when you use a parameterized struct. In this case, when you create an instance of GenericArray, you need to specify the type you want to store, like Int, or Float64. (This is a little confusing, because the parameter value you're passing in this case is a type. That's OK: a Mojo type is a valid compile-time value.)\n\nYou'll see that ElementType is used throughout the struct where you'd usually see a type name. For example, as the formal type for the elements in the constructor, and the return type of the __getitem__() method.\n\nHere's an example of using GenericArray:\n\nvar array = GenericArray[Int](1, 2, 3, 4)\nfor i in range(array.size):\n print(array[i], end=\" \")\n\n1 2 3 4\n\nA parameterized struct can use the Self type to represent a concrete instance of the struct (that is, with all its parameters specified). For example, you could add a static factory method to GenericArray with the following signature:\n\nstruct GenericArray[ElementType: CollectionElement]:\n ...\n\n @staticmethod\n fn splat(count: Int, value: ElementType) -> Self:\n # Create a new array with count instances of the given value\n\nHere, Self is equivalent to writing GenericArray[ElementType]. That is, you can call the splat() method like this:\n\nGenericArray[Float64].splat(8, 0)\n\nThe method returns an instance of GenericArray[Float64].\nConditional conformance\n\nWhen creating a generic struct, you might want to define some methods that require extra features. For example, consider a collection like GenericArray that holds instances of CollectionElement. The CollectionElement trait only requires that the stored data type be copyable and movable. This imposes a lot of limitations: you can't implement a sort() method because you can't guarantee that the stored type supports the comparison operators; you can't write a useful __str__() or __repr__() dunder method because you can't guarantee that the stored type supports conversion to a string.\n\nThe answer to these issues is conditional conformance, which lets you define a method that requires additional features. You do this by defining the self value that has a more specific bound on one or more of its parameters.\n\nFor example, the following code defines a Container type that holds an instance of CollectionElement. It also defines a __str__() method that can only be called if the stored ElementType conforms to StringableCollectionElement:\n\n@value\nstruct Container[ElementType: CollectionElement]:\n var element: ElementType\n\n def __str__[StrElementType: StringableCollectionElement, //](\n self: Container[StrElementType]) -> String:\n return str(self.element)\n\ndef use_container():\n float_container = Container(5)\n string_container = Container(\"Hello\")\n print(float_container.__str__())\n print(string_container.__str__())\n\nuse_container()\n\n5\nHello\n\nNote the signature of the __str__() method, which declares the self argument with a more specific type. Specifically, it declares that it takes a Container with an ElementType that conforms to the StringableCollectionElement trait.\n\ndef __str__[StrElementType: StringableCollectionElement, //](\n self: Container[StrElementType]) -> String:\n\nThis trait must be a superset of ElementType's original trait: for example, StringableCollectionElement inherits from CollectionElement, so it includes all of requirements of the original trait.\n\nNote that the use_container() function calls the __str__() method directly, rather than calling str(float_container). One current limitation of conditional conformance is that Mojo can't recognize the struct Container[Int] as conforming to Stringable, even though the __str__() method is implemented for any ElementType that's also Stringable.\nCase study: the SIMD type\n\nFor a real-world example of a parameterized type, let's look at the SIMD type from Mojo's standard library.\n\nSingle instruction, multiple data (SIMD) is a parallel processing technology built into many modern CPUs, GPUs, and custom accelerators. SIMD allows you to perform a single operation on multiple pieces of data at once. For example, if you want to take the square root of each element in an array, you can use SIMD to parallelize the work.\n\nProcessors implement SIMD using low-level vector registers in hardware that hold multiple instances of a scalar data type. In order to use the SIMD instructions on these processors, the data must be shaped into the proper SIMD width (data type) and length (vector size). Processors may support 512-bit or longer SIMD vectors, and support many data types from 8-bit integers to 64-bit floating point numbers, so it's not practical to define all of the possible SIMD variations.\n\nMojo's SIMD type (defined as a struct) exposes the common SIMD operations through its methods, and makes the SIMD data type and size values parametric. This allows you to directly map your data to the SIMD vectors on any hardware.\n\nHere's a cut-down (non-functional) version of Mojo's SIMD type definition:\n\nstruct SIMD[type: DType, size: Int]:\n var value: … # Some low-level MLIR stuff here\n\n # Create a new SIMD from a number of scalars\n fn __init__(inout self, *elems: SIMD[type, 1]): ...\n\n # Fill a SIMD with a duplicated scalar value.\n @staticmethod\n fn splat(x: SIMD[type, 1]) -> SIMD[type, size]: ...\n\n # Cast the elements of the SIMD to a different elt type.\n fn cast[target: DType](self) -> SIMD[target, size]: ...\n\n # Many standard operators are supported.\n fn __add__(self, rhs: Self) -> Self: ...\n\nSo you can create and use a SIMD vector like this:\n\nvar vector = SIMD[DType.int16, 4](1, 2, 3, 4)\nvector = vector * vector\nfor i in range(4):\n print(vector[i], end=\" \")\n\n1 4 9 16\n\nAs you can see, a simple arithmetic operator like * applied to a pair of SIMD vector operates on the corresponding elements in each vector.\n\nDefining each SIMD variant with parameters is great for code reuse because the SIMD type can express all the different vector variants statically, instead of requiring the language to pre-define every variant.\n\nBecause SIMD is a parameterized type, the self argument in its functions carries those parameters—the full type name is SIMD[type, size]. Although it's valid to write this out (as shown in the return type of splat()), this can be verbose, so we recommend using the Self type (from PEP673) like the __add__ example does.\nOverloading on parameters\n\nFunctions and methods can be overloaded on their parameter signatures. The overload resolution logic filters for candidates according to the following rules, in order of precedence:\n\n Candidates with the minimal number of implicit conversions (in both arguments and parameters).\n Candidates without variadic arguments.\n Candidates without variadic parameters.\n Candidates with the shortest parameter signature.\n Non-@staticmethod candidates (over @staticmethod ones, if available).\n\nIf there is more than one candidate after applying these rules, the overload resolution fails. For example:\n\n@register_passable(\"trivial\")\nstruct MyInt:\n \"\"\"A type that is implicitly convertible to `Int`.\"\"\"\n var value: Int\n\n @always_inline(\"nodebug\")\n fn __init__(inout self, _a: Int):\n self.value = _a\n\nfn foo[x: MyInt, a: Int]():\n print(\"foo[x: MyInt, a: Int]()\")\n\nfn foo[x: MyInt, y: MyInt]():\n print(\"foo[x: MyInt, y: MyInt]()\")\n\nfn bar[a: Int](b: Int):\n print(\"bar[a: Int](b: Int)\")\n\nfn bar[a: Int](*b: Int):\n print(\"bar[a: Int](*b: Int)\")\n\nfn bar[*a: Int](b: Int):\n print(\"bar[*a: Int](b: Int)\")\n\nfn parameter_overloads[a: Int, b: Int, x: MyInt]():\n # `foo[x: MyInt, a: Int]()` is called because it requires no implicit\n # conversions, whereas `foo[x: MyInt, y: MyInt]()` requires one.\n foo[x, a]()\n\n # `bar[a: Int](b: Int)` is called because it does not have variadic\n # arguments or parameters.\n bar[a](b)\n\n # `bar[*a: Int](b: Int)` is called because it has variadic parameters.\n bar[a, a, a](b)\n\nparameter_overloads[1, 2, MyInt(3)]()\n\nstruct MyStruct:\n fn __init__(inout self):\n pass\n\n fn foo(inout self):\n print(\"calling instance method\")\n\n @staticmethod\n fn foo():\n print(\"calling static method\")\n\nfn test_static_overload():\n var a = MyStruct()\n # `foo(inout self)` takes precedence over a static method.\n a.foo()\n\nfoo[x: MyInt, a: Int]()\nbar[a: Int](b: Int)\nbar[*a: Int](b: Int)\nUsing parameterized types and functions\n\nYou can use parametric types and functions by passing values to the parameters in square brackets. For example, for the SIMD type above, type specifies the data type and size specifies the length of the SIMD vector (it must be a power of 2):\n\n# Make a vector of 4 floats.\nvar small_vec = SIMD[DType.float32, 4](1.0, 2.0, 3.0, 4.0)\n\n# Make a big vector containing 1.0 in float16 format.\nvar big_vec = SIMD[DType.float16, 32](1.0)\n\n# Do some math and convert the elements to float32.\nvar bigger_vec = (big_vec+big_vec).cast[DType.float32]()\n\n# You can write types out explicitly if you want of course.\nvar bigger_vec2 : SIMD[DType.float32, 32] = bigger_vec\n\nprint('small_vec type:', small_vec.element_type, 'length:', len(small_vec))\nprint('bigger_vec2 type:', bigger_vec2.element_type, 'length:', len(bigger_vec2))\n\nsmall_vec type: float32 length: 4\nbigger_vec2 type: float32 length: 32\n\nNote that the cast() method also needs a parameter to specify the type you want from the cast (the method definition above expects a target parametric value). Thus, just as the SIMD struct is a generic type definition, the cast() method is a generic method definition. At compile time, the compiler creates a concrete version of the cast() method with the target parameter bound to DType.float32.\n\nThe code above shows the use of concrete types (that is, the parameters are all bound to known values). But the major power of parameters comes from the ability to define parametric algorithms and types (code that uses the parameter values). For example, here's how to define a parametric algorithm with SIMD that is type- and width-agnostic:\n\nfrom math import sqrt\n\nfn rsqrt[dt: DType, width: Int](x: SIMD[dt, width]) -> SIMD[dt, width]:\n return 1 / sqrt(x)\n\nvar v = SIMD[DType.float16, 4](42)\nprint(rsqrt(v))\n\n[0.154296875, 0.154296875, 0.154296875, 0.154296875]\n\nNotice that the x argument is actually a SIMD type based on the function parameters. The runtime program can use the value of the parameters, because the parameters are resolved at compile-time before they are needed by the runtime program (but compile-time parameter expressions cannot use runtime values).\nParameter inference\n\nThe Mojo compiler can often infer parameter values, so you don't always have to specify them. For example, you can call the rsqrt() function defined above without any parameters:\n\nvar v = SIMD \nprint(rsqrt(v))\n\n[0.174072265625, 0.174072265625, 0.174072265625, 0.174072265625]\n\nThe compiler infers its parameters based on the parametric v value passed into it, as if you wrote rsqrt[DType.float16, 4](v) explicitly.\n\nMojo can also infer the values of struct parameters from the arguments passed to a constructor or static method.\n\nFor example, consider the following struct:\n\n@value\nstruct One[Type: StringableCollectionElement]:\n var value: Type\n\n fn __init__(inout self, value: Type):\n self.value = value\n\ndef use_one():\n s1 = One(123)\n s2 = One(\"Hello\")\n\nNote that you can create an instance of One without specifying the Type parameter—Mojo can infer it from the value argument.\n\nYou can also infer parameters from a parameterized type passed to a constructor or static method:\n\nstruct Two[Type: StringableCollectionElement]:\n var val1: Type\n var val2: Type\n\n fn __init__(inout self, one: One[Type], another: One[Type]):\n self.val1 = one.value\n self.val2 = another.value\n print(str(self.val1), str(self.val2))\n\n @staticmethod\n fn fire(thing1: One[Type], thing2: One[Type]):\n print(\"🔥\", str(thing1.value), str(thing2.value))\n\ndef use_two():\n s3 = Two(One(\"infer\"), One(\"me\"))\n Two.fire(One(1), One(2))\n\nuse_two()\n\ninfer me\n🔥 1 2\n\nTwo takes a Type parameter, and its constructor takes values of type One[Type]. When constructing an instance of Two, you don't need to specify the Type parameter, since it can be inferred from the arguments.\n\nSimilarly, the static fire() method takes values of type One[Type], so Mojo can infer the Type value at compile time.\nnote\n\nIf you're familiar with C++, you may recognize this as similar to Class Template Argument Deduction (CTAD).\nOptional parameters and keyword parameters\n\nJust as you can specify optional arguments in function signatures, you can also define an optional parameter by giving it a default value.\n\nYou can also pass parameters by keyword, just like you can use keyword arguments. For a function or struct with multiple optional parameters, using keywords allows you to pass only the parameters you want to specify, regardless of their position in the function signature.\n\nFor example, here's a function with two parameters, each with a default value:\n\nfn speak[a: Int = 3, msg: StringLiteral = \"woof\"]():\n print(msg, a)\n\nfn use_defaults() raises:\n speak() # prints 'woof 3'\n speak[5]() # prints 'woof 5'\n speak[7, \"meow\"]() # prints 'meow 7'\n speak[msg=\"baaa\"]() # prints 'baaa 3'\n\nRecall that when a parametric function is called, Mojo can infer the parameter values. That is, it can use the parameter values attached to an argument value (see the sqrt[]() example above). If the parametric function also has a default value defined, then the inferred parameter type takes precedence.\n\nFor example, in the following code, we update the parametric speak[]() function to take an argument with a parametric type. Although the function has a default parameter value for a, Mojo instead uses the inferred a parameter value from the bar argument (as written, the default a value can never be used, but this is just for demonstration purposes):\n\n@value\nstruct Bar[v: Int]:\n pass\n\nfn speak[a: Int = 3, msg: StringLiteral = \"woof\"](bar: Bar[a]):\n print(msg, a)\n\nfn use_inferred():\n speak(Bar[9]()) # prints 'woof 9'\n\nAs mentioned above, you can also use optional parameters and keyword parameters in a struct:\n\nstruct KwParamStruct[greeting: String = \"Hello\", name: String = \"🔥mojo🔥\"]:\n fn __init__(inout self):\n print(greeting, name)\n\nfn use_kw_params():\n var a = KwParamStruct[]() # prints 'Hello 🔥mojo🔥'\n var b = KwParamStruct[name=\"World\"]() # prints 'Hello World'\n var c = KwParamStruct[greeting=\"Hola\"]() # prints 'Hola 🔥mojo🔥'\n\nnote\n\nMojo supports positional-only and keyword-only parameters, following the same rules as positional-only and keyword-only arguments.\nInfer-only parameters\n\nSometimes you need to declare functions where parameters depend on other parameters. Because the signature is processed left to right, a parameter can only depend on a parameter earlier in the parameter list. For example:\n\nfn dependent_type[dtype: DType, value: Scalar[dtype]]():\n print(\"Value: \", value)\n print(\"Value is floating-point: \", dtype.is_floating_point())\n\ndependent_type[DType.float64, Float64(2.2)]()\n\nValue: 2.2000000000000002\nValue is floating-point: True\n\nYou can't reverse the position of the dtype and value parameters, because value depends on dtype. However, because dtype is a required parameter, you can't leave it out of the parameter list and let Mojo infer it from value:\n\ndependent_type[Float64(2.2)]() # Error!\n\nInfer-only parameters are a special class of parameters that are always inferred from context. Infer-only parameters are placed at the beginning of the parameter list, set off from other parameters by the // sigil:\n\nfn example[type: CollectionElement, //, list: List[type]]()\n\nTransforming dtype into an infer-only parameter solves this problem:\n\nfn dependent_type[dtype: DType, //, value: Scalar[dtype]]():\n print(\"Value: \", value)\n print(\"Value is floating-point: \", dtype.is_floating_point())\n\ndependent_type[Float64(2.2)]()\n\nValue: 2.2000000000000002\nValue is floating-point: True\n\nBecause infer-only parameters are declared at the beginning of the parameter list, other parameters can depend on them, and the compiler will always attempt to infer the infer-only values from bound parameters or arguments.\n\nIf the compiler can't infer the value of an infer-only parameter, compilation fails.\nVariadic parameters\n\nMojo also supports variadic parameters, similar to Variadic arguments:\n\nstruct MyTensor[*dimensions: Int]:\n pass\n\nVariadic parameters currently have some limitations that variadic arguments don't have:\n\n Variadic parameters must be homogeneous—that is, all the values must be the same type.\n\n The parameter type must be register-passable.\n\n The parameter values aren't automatically projected into a VariadicList, so you need to construct the list explicitly:\n\nfn sum_params[*values: Int]() -> Int:\n alias list = VariadicList(values)\n var sum = 0\n for v in list:\n sum += v\n return sum\n\nVariadic keyword parameters (for example, **kwparams) are not supported yet.\nParameter expressions are just Mojo code\n\nA parameter expression is any code expression (such as a+b) that occurs where a parameter is expected. Parameter expressions support operators and function calls, just like runtime code, and all parameter types use the same type system as the runtime program (such as Int and DType).\n\nBecause parameter expressions use the same grammar and types as runtime Mojo code, you can use many \"dependent type\" features. For example, you might want to define a helper function to concatenate two SIMD vectors:\n\nfn concat[ty: DType, len1: Int, len2: Int](\n lhs: SIMD[ty, len1], rhs: SIMD[ty, len2]) -> SIMD[ty, len1+len2]:\n\n var result = SIMD[ty, len1 + len2]()\n for i in range(len1):\n result[i] = SIMD[ty, 1](lhs[i])\n for j in range(len2):\n result[len1 + j] = SIMD[ty, 1](rhs[j])\n return result\n\nvar a = SIMD[DType.float32, 2](1, 2)\nvar x = concat(a, a)\n\nprint('result type:', x.element_type, 'length:', len(x))\n\nresult type: float32 length: 4\n\nNote that the resulting length is the sum of the input vector lengths, and this is expressed with a simple + operation.\nPowerful compile-time programming\n\nWhile simple expressions are useful, sometimes you want to write imperative compile-time logic with control flow. You can even do compile-time recursion. For instance, here is an example \"tree reduction\" algorithm that sums all elements of a vector recursively into a scalar:\n\nfn slice[ty: DType, new_size: Int, size: Int](\n x: SIMD[ty, size], offset: Int) -> SIMD[ty, new_size]:\n var result = SIMD[ty, new_size]()\n for i in range(new_size):\n result[i] = SIMD[ty, 1](x[i + offset])\n return result\n\nfn reduce_add[ty: DType, size: Int](x: SIMD[ty, size]) -> Int:\n @parameter\n if size == 1:\n return int(x[0])\n elif size == 2:\n return int(x[0]) + int(x[1])\n\n # Extract the top/bottom halves, add them, sum the elements.\n alias half_size = size // 2\n var lhs = slice[ty, half_size, size](x, 0)\n var rhs = slice[ty, half_size, size](x, half_size)\n return reduce_add[ty, half_size](lhs + rhs)\n\nvar x = SIMD[DType.index, 4](1, 2, 3, 4)\nprint(x)\nprint(\"Elements sum:\", reduce_add(x))\n\n[1, 2, 3, 4]\nElements sum: 10\n\nThis makes use of the @parameter decorator to create a parametric if condition, which is an if statement that runs at compile-time. It requires that its condition be a valid parameter expression, and ensures that only the live branch of the if statement is compiled into the program. (This is similar to use of the @parameter decorator with a for loop shown earlier.)\nMojo types are just parameter expressions\n\nWhile we've shown how you can use parameter expressions within types, type annotations can themselves be arbitrary expressions (just like in Python). Types in Mojo have a special metatype type, allowing type-parametric algorithms and functions to be defined.\n\nFor example, we can create a simplified Array that supports arbitrary types of elements (via the AnyTrivialRegType parameter):\n\nfrom memory import UnsafePointer\n\nstruct Array[T: AnyTrivialRegType]:\n var data: UnsafePointer[T]\n var size: Int\n\n fn __init__(inout self, size: Int, value: T):\n self.size = size\n self.data = UnsafePointer[T].alloc(self.size)\n for i in range(self.size):\n (self.data + i).init_pointee_copy(value)\n\n fn __getitem__(self, i: Int) -> T:\n return self.data[i]\n\n fn __del__(owned self):\n for i in range(self.size):\n (self.data + i).destroy_pointee()\n self.data.free()\n\nvar v = Array[Float32](4, 3.14)\nprint(v[0], v[1], v[2], v[3])\n\nNotice that the T parameter is being used as the formal type for the value arguments and the return type of the __getitem__() function. Parameters allow the Array type to provide different APIs based on the different use-cases.\n\nThere are many other cases that benefit from more advanced use of parameters. For example, you can execute a closure N times in parallel, feeding in a value from the context, like this:\n\nfn parallelize[func: fn (Int) -> None](num_work_items: Int):\n # Not actually parallel: see the 'algorithm' module for real implementation.\n for i in range(num_work_items):\n func(i)\n\nAnother example where this is important is with variadic generics, where an algorithm or data structure may need to be defined over a list of heterogeneous types such as for a tuple. Right now, this is not fully supported in Mojo and requires writing some MLIR by hand. In the future, this will be possible in pure Mojo.\nalias: named parameter expressions\n\nIt is very common to want to name compile-time values. Whereas var defines a runtime value, we need a way to define a compile-time temporary value. For this, Mojo uses an alias declaration.\n\nFor example, the DType struct implements a simple enum using aliases for the enumerators like this (the actual DType implementation details vary a bit):\n\nstruct DType:\n var value : UI8\n alias invalid = DType(0)\n alias bool = DType(1)\n alias int8 = DType(2)\n alias uint8 = DType(3)\n alias int16 = DType(4)\n alias int16 = DType(5)\n ...\n alias float32 = DType(15)\n\nThis allows clients to use DType.float32 as a parameter expression (which also works as a runtime value) naturally. Note that this is invoking the runtime constructor for DType at compile-time.\n\nTypes are another common use for aliases. Because types are compile-time expressions, it is handy to be able to do things like this:\n\nalias Float16 = SIMD[DType.float16, 1]\nalias UInt8 = SIMD[DType.uint8, 1]\n\nvar x: Float16 = 0 # Float16 works like a \"typedef\"\n\nLike var variables, aliases obey scope, and you can use local aliases within functions as you'd expect.\nFully-bound, partially-bound, and unbound types\n\nA parametric type with its parameters specified is said to be fully-bound. That is, all of its parameters are bound to values. As mentioned before, you can only instantiate a fully-bound type (sometimes called a concrete type).\n\nHowever, parametric types can be unbound or partially bound in some contexts. For example, you can alias a partially-bound type to create a new type that requires fewer parameters:\n\nfrom collections import Dict\n\nalias StringKeyDict = Dict[String, _]\nvar b = StringKeyDict[UInt8]()\nb[\"answer\"] = 42\n\nHere, StringKeyDict is a type alias for a Dict that takes String keys. The underscore _ in the parameter list indicates that the second parameter, V (the value type), is unbound. You specify the V parameter later, when you use StringKeyDict.\n\nFor example, given the following type:\n\nstruct MyType[s: String, i: Int, i2: Int, b: Bool = True]:\n pass\n\nIt can appear in code in the following forms:\n\n Fully bound, with all of its parameters specified:\n\n MyType[\"Hello\", 3, 4, True]\n\nPartially bound, with some but not all of its parameters specified:\n\nMyType[\"Hola\", _, _, True]\n\nUnbound, with no parameters specified:\n\nMyType[_, _, _, _]\n\nYou can also use the star-underscore expression *_ to unbind an arbitrary number of positional parameters at the end of a parameter list.\n\n# These two types are equivalent\nMyType[\"Hello\", *_]\nMyType[\"Hello\", _, _, _]\n\nWhen a parameter is explicitly unbound with the _ or *_ expression, you must specify a value for that parameter to use the type. Any default value from the original type declaration is ignored.\n\nPartially-bound and unbound parametric types can be used in some contexts where the missing (unbound) parameters will be supplied later—such as in aliases and automatically parameterized functions.\nOmitted parameters\n\nMojo also supports an alternate format for unbound parameter where the parameter is simply omitted from the expression:\n\n# Partially bound\nMyType[\"Hi there\"]\n# Unbound\nMyType\n\nThis format differs from the explicit unbinding syntax described above in that the default values for omitted parameters are bound immediately. For example, the following expressions are equivalent:\n\nMyType[\"Hi there\"]\n# equivalent to\nMyType[\"Hi there\", _, _, True] # Uses the default value for `b`\n\nnote\n\nThis format is currently supported for backwards compatibility. We intend to deprecate this format in the future in favor of the explicit unbinding syntax.\nAutomatic parameterization of functions\n\nMojo supports \"automatic\" parameterization of functions. If a function argument type is a partially-bound or unbound type, the unbound parameters are automatically added as input parameters on the function. This is easier to understand with an example:\n\nfn print_params(vec: SIMD[*_]):\n print(vec.type)\n print(vec.size)\n\nvar v = SIMD[DType.float64, 4](1.0, 2.0, 3.0, 4.0)\nprint_params(v)\n\nfloat64\n4\n\nIn the above example, the print_params function is automatically parameterized. The vec argument takes an argument of type SIMD[*_]. This is an unbound parameterized type—that is, it doesn't specify any parameter values for the type. Mojo treats the unbound parameters on vec as implicit parameters on the function. This is roughly equivalent to the following code, which includes explicit input parameters:\n\nfn print_params[t: DType, s: Int](vec: SIMD[t, s]):\n print(vec.type)\n print(vec.size)\n\nWhen you call print_params() you must pass it a concrete instance of the SIMD type—that is, one with all of its parameters specified, like SIMD[DType.float64, 4]. The Mojo compiler infers the parameter values from the input argument.\n\nWith a manually parameterized function, you can access the input parameters by name (for example, t and s in the previous example). For an automatically parameterized function, you can access the parameters as attributes on the argument (for example, vec.type).\n\nThis ability to access a type's input parameters is not specific to automatically parameterized functions, you can use it anywhere. You can access the input parameters of a parameterized type as attributes on the type itself:\n\nfn on_type():\n print(SIMD[DType.float32, 2].size) # prints 2\n\nOr as attributes on an instance of the type:\n\nfn on_instance():\n var x = SIMD[DType.int32, 2](4, 8)\n print(x.type) # prints int32\n\nYou can even use this syntax in the function's signature to define a function's arguments and return type based on an argument's parameters. For example, if you want your function to take two SIMD vectors with the same type and size, you can write code like this:\n\nfn interleave(v1: SIMD, v2: __type_of(v1)) -> SIMD[v1.type, v1.size*2]:\n var result = SIMD[v1.type, v1.size*2]()\n for i in range(v1.size):\n result[i*2] = SIMD[v1.type, 1](v1[i])\n result[i*2+1] = SIMD[v1.type, 1](v2[i])\n return result\n\nvar a = SIMD[DType.int16, 4](1, 2, 3, 4)\nvar b = SIMD[DType.int16, 4](0, 0, 0, 0)\nvar c = interleave(a, b)\nprint(c)\n\n[1, 0, 2, 0, 3, 0, 4, 0]\n\nAs shown in the example, you can use the magic __type_of(x) call if you just want to match the type of an argument. In this case, it's more convenient and compact that writing the equivalent SIMD[v1.type, v1.size].\nAutomatic parameterization with partially-bound types\n\nMojo also supports automatic parameterization: with partially-bound parameterized types (that is, types with some but not all of the parameters specified).\n\nFor example, suppose we have a Fudge struct with three parameters:\n\n@value\nstruct Fudge[sugar: Int, cream: Int, chocolate: Int = 7](Stringable):\n fn __str__(self) -> String:\n return str(\"Fudge (\") + str(sugar) + \",\" +\n str(cream) + \",\" + str(chocolate) + \")\"\n\nWe can write a function that takes a Fudge argument with just one bound parameter (it's partially bound):\n\nfn eat(f: Fudge[5, *_]):\n print(\"Ate \" + str(f))\n\nThe eat() function takes a Fudge struct with the first parameter (sugar) bound to the value 5. The second and third parameters, cream and chocolate are unbound.\n\nThe unbound cream and chocolate parameters become implicit input parameters on the eat function. In practice, this is roughly equivalent to writing:\n\nfn eat[cr: Int, ch: Int](f: Fudge[5, cr, ch]):\n print(\"Ate\", str(f))\n\nIn both cases, we can call the function by passing in an instance with the cream and chocolate parameters bound:\n\neat(Fudge[5, 5, 7]())\neat(Fudge[5, 8, 9]())\n\nAte Fudge (5,5,7)\nAte Fudge (5,8,9)\n\nIf you try to pass in an argument with a sugar value other than 5, compilation fails, because it doesn't match the argument type:\n\neat(Fudge[12, 5, 7]())\n# ERROR: invalid call to 'eat': argument #0 cannot be converted from 'Fudge[12, 5, 7]' to 'Fudge[5, 5, 7]'\n\nYou can also explicitly unbind individual parameters. This gives you more freedom in specifying unbound parameters.\n\nFor example, you might want to let the user specify values for sugar and chocolate, and leave cream constant. To do this, replace each unbound parameter value with a single underscore (_):\n\nfn devour(f: Fudge[_, 6, _]):\n print(\"Devoured\", str(f))\n\nAgain, the unbound parameters (sugar and chocolate) are added as implicit input parameters on the function. This version is roughly equivalent to the following code, where these two values are explicitly bound to the input parameters, su and ch:\n\nfn devour[su: Int, ch: Int](f: Fudge[su, 6, ch]):\n print(\"Devoured\", str(f))\n\nYou can also specify parameters by keyword, or mix positional and keyword parameters, so the following function is roughly equivalent to the previous one: the first parameter, sugar is explicitly unbound with the underscore character. The chocolate parameter is unbound using the keyword syntax, chocolate=_. And cream is explicitly bound to the value 6:\n\nfn devour(f: Fudge[_, chocolate=_, cream=6]):\n print(\"Devoured\", str(f))\n\nAll three versions of the devour() function work with the following calls:\n\ndevour(Fudge[3, 6, 9]())\ndevour(Fudge[4, 6, 8]())\n\nDevoured Fudge (3,6,9)\nDevoured Fudge (4,6,8)\nLegacy syntax (omitted parameters)\n\nYou can also specify an unbound or partially-bound type by omitting parameters: for example:\n\nfn nibble(f: Fudge[5]):\n print(\"Ate\", str(f))\n\nHere, Fudge[5] works like Fudge[5, *_] except in the handling of parameters with default values. Instead of discarding the default value of chocolate, Fudge[5] binds the default value immediately, making it equivalent to: Fudge[5, _, 7].\n\nThis means that the following code won't compile with the previous definition for nibble() function, since it doesn't use the default value for chocolate:\n\nnibble(Fudge[5, 5, 9]())\n# ERROR: invalid call to 'eat': argument #0 cannot be converted from 'Fudge[5, 5, 9]' to 'Fudge[5, 5, 7]'\n\nTODO\n\nSupport for omitting unbound parameters will eventually be deprecated in favor of explicitly unbound parameters using _ and *_.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/parameters",
"description": "Parameterization: Metaprogramming in Mojo"
}
]
}
]
},
{
"section": "Pointers",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Unsafe Pointers",
"description": "Learning about Pointers in Mojo",
"page_count": 1
},
"content": "Unsafe pointers\n\nThe UnsafePointer type creates an indirect reference to a location in memory. You can use an UnsafePointer to dynamically allocate and free memory, or to point to memory allocated by some other piece of code. You can use these pointers to write code that interacts with low-level interfaces, to interface with other programming languages, or to build certain kinds of data structures. But as the name suggests, they're inherently unsafe. For example, when using unsafe pointers, you're responsible for ensuring that memory gets allocated and freed correctly.\nnote\n\nIn addition to unsafe pointers, Mojo supports a safe Reference type. See UnsafePointer and Reference for a brief comparison of the types.\nWhat is a pointer?\n\nAn UnsafePointer is a type that holds an address to memory. You can store and retrieve values in that memory. The UnsafePointer type is generic—it can point to any type of value, and the value type is specified as a parameter. The value pointed to by a pointer is sometimes called a pointee.\n\nfrom memory.unsafe_pointer import UnsafePointer\n\n# Allocate memory to hold a value\nvar ptr = UnsafePointer[Int].alloc(1)\n# Initialize the allocated memory\nptr.init_pointee_copy(100)\n\nFigure 1. Pointer and pointee\n\nAccessing the memory—to retrieve or update a value—is called dereferencing the pointer. You can dereference a pointer by following the variable name with an empty pair of square brackets:\n\n# Update an initialized value\nptr[] += 10\n# Access an initialized value\nprint(ptr[])\n\n110\n\nYou can also allocate memory to hold multiple values to build array-like structures. For details, see Storing multiple values.\nLifecycle of a pointer\n\nAt any given time, a pointer can be in one of several states:\n\n Uninitialized. Just like any variable, a variable of type UnsafePointer can be declared but uninitialized.\n\n var ptr: UnsafePointer[Int]\n\nNull. A null pointer has an address of 0, indicating an invalid pointer.\n\nptr = UnsafePointer[Int]()\n\nPointing to allocated, uninitialized memory. The alloc() static method returns a pointer to a newly-allocated block of memory with space for the specified number of elements of the pointee's type.\n\nptr = UnsafePointer[Int].alloc(1)\n\nTrying to dereference a pointer to uninitialized memory results in undefined behavior.\n\nPointing to initialized memory. You can initialize an allocated, uninitialized pointer by moving or copying an existing value into the memory. Or you can use the address_of() static method to get a pointer to an existing value.\n\nptr.init_pointee_copy(value)\n# or\nptr.init_pointee_move(value^)\n# or\nptr = UnsafePointer[Int].address_of(value)\n\nOnce the value is initialized, you can read or mutate it using the dereference syntax:\n\noldValue = ptr[]\nptr[] = newValue\n\nDangling. When you free the pointer's allocated memory, you're left with a dangling pointer. The address still points to its previous location, but the memory is no longer allocated to this pointer. Trying to dereference the pointer, or calling any method that would access the memory location results in undefined behavior.\n\nptr.free()\n\nThe following diagram shows the lifecycle of an UnsafePointer:\n\nFigure 2. Lifecycle of an UnsafePointer\nAllocating memory\n\nUse the static alloc() method to allocate memory. The method returns a new pointer pointing to the requested memory. You can allocate space for one or more values of the pointee's type.\n\nptr = UnsafePointer[Int].alloc(10) # Allocate space for 10 Int values\n\nThe allocated space is uninitialized—like a variable that's been declared but not initialized.\nInitializing the pointee\n\nTo initialize allocated memory, UnsafePointer provides the init_pointee_copy() and init_pointee_move() methods. For example:\n\nptr.init_pointee_copy(my_value)\n\nTo move a value into the pointer's memory location, use init_pointee_move():\n\nstr_ptr.init_pointee_move(my_string^)\n\nNote that to move the value, you usually need to add the transfer sigil (^), unless the value is a trivial type (like Int) or a newly-constructed, \"owned\" value:\n\nstr_ptr.init_pointee_move(str(\"Owned string\"))\n\nAlternately, you can get a pointer to an existing value using the static address_of() method. This is useful for getting a pointer to a value on the stack, for example.\n\nvar counter: Int = 5\nptr = UnsafePointer[Int].address_of(counter)\n\nNote that when calling address_of(), you don't need to allocate memory ahead of time, since you're pointing to an existing value.\nDereferencing pointers\n\nUse the [] dereference operator to access the value stored at a pointer (the \"pointee\").\n\n# Read from pointee\nprint(ptr[])\n# mutate pointee\nptr[] = 0\n\n5\n\nIf you've allocated space for multiple values, you can use subscript syntax to access the values, as if they were an array, like ptr[3]. The empty subscript [] has the same meaning as [0].\ncaution\n\nThe dereference operator assumes that the memory being dereferenced is initialized. Dereferencing uninitialized memory results in undefined behavior.\n\nYou cannot safely use the dereference operator on uninitialized memory, even to initialize a pointee. This is because assigning to a dereferenced pointer calls lifecycle methods on the existing pointee (such as the destructor, move constructor or copy constructor).\n\nstr_ptr = UnsafePointer[String].alloc(1)\n# str_ptr[] = \"Testing\" # Undefined behavior!\nstr_ptr.init_pointee_move(\"Testing\")\nstr_ptr[] += \" pointers\" # Works now\n\nDestroying or removing values\n\nThe take_pointee() method moves the pointee from the memory location pointed to by ptr. This is a consuming move—it invokes __moveinit__() on the destination value. It leaves the memory location uninitialized.\n\nThe destroy_pointee() method calls the destructor on the pointee, and leaves the memory location pointed to by ptr uninitialized.\n\nBoth take_pointee() and destroy_pointee() require that the pointer is non-null, and the memory location contains a valid, initialized value of the pointee's type; otherwise the function results in undefined behavior.\n\nThe move_pointee_into(self, dst) method moves the pointee from one pointer location to another. Both pointers must be non-null. The source location must contain a valid, initialized value of the pointee's type, and is left uninitialized after the call. The destination location is assumed to be uninitialized—if it contains a valid value, that value's destructor is not run. The value from the source location is moved to the destination location as a consuming move. This function also has undefined behavior if any of its prerequisites is not met.\nFreeing memory\n\nCalling free() on a pointer frees the memory allocated by the pointer. It doesn't call the destructors on any values stored in the memory—you need to do that explicitly (for example, using destroy_pointee() or one of the other functions described in Destroying or removing values).\n\nDisposing of a pointer without freeing the associated memory can result in a memory leak—where your program keeps taking more and more memory, because not all allocated memory is being freed.\n\nOn the other hand, if you have multiple copies of a pointer accessing the same memory, you need to make sure you only call free() on one of them. Freeing the same memory twice is also an error.\n\nAfter freeing a pointer's memory, you're left with a dangling pointer—its address still points to the freed memory. Any attempt to access the memory, like dereferencing the pointer results in undefined behavior.\nStoring multiple values\n\nAs mentioned in Allocating memory, you can use an UnsafePointer to allocate memory for multiple values. The memory is allocated as a single, contiguous block. Pointers support arithmetic: adding an integer to a pointer returns a new pointer offset by the specified number of values from the original pointer:\n\nthird_ptr = first_ptr + 2\n\nPointers also support subtraction, as well as in-place addition and subtraction:\n\n# Advance the pointer one element:\nptr += 1\n\nFigure 3. Pointer arithmetic\n\nFor example, the following example allocates memory to store 6 Float64 values, and initializes them all to zero.\n\nfloat_ptr = UnsafePointer[Float64].alloc(6)\nfor offset in range(6):\n (float_ptr+offset).init_pointee_copy(0.0)\n\nOnce the values are initialized, you can access them using subscript syntax:\n\nfloat_ptr[2] = 3.0\nfor offset in range(6):\n print(float_ptr[offset], end=\", \")\n\n0.0, 0.0, 3.0, 0.0, 0.0, 0.0,\nWorking with foreign pointers\n\nWhen exchanging data with other programming languages, you may need to construct an UnsafePointer from an a foreign pointer. Mojo restricts creating UnsafePointer instances from arbitrary addresses, to avoid users accidentally creating pointers that alias each other (that is, two pointers that refer to the same location). However, there are specific methods you can use to get an UnsafePointer from a Python or C/C++ pointer.\n\nWhen dealing with memory allocated elsewhere, you need to be aware of who's responsible for freeing the memory. Freeing memory allocated elsewhere can result in undefined behavior.\n\nYou also need to be aware of the format of the data stored in memory, including data types and byte order. For more information, see Converting data: bitcasting and byte order.\nCreating a Mojo pointer from a Python pointer\n\nThe PythonObject type defines an unsafe_get_as_pointer() method to construct an UnsafePointer from a Python address.\n\nFor example, the following code creates a NumPy array and then accesses the data using a Mojo pointer:\n\nfrom python import Python\nfrom memory.unsafe_pointer import UnsafePointer\n\ndef share_array():\n np = Python.import_module(\"numpy\")\n arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])\n ptr = arr.__array_interface__[\"data\"][0].unsafe_get_as_pointer[DType.int64]()\n for i in range(9):\n print(ptr[i], end=\", \")\n\nshare_array()\n\n1, 2, 3, 4, 5, 6, 7, 8, 9,\n\nNumPy arrays implement the array interface protocol, which defines the __array_interface__ object used in the example, where __array_interface__[\"data\"][0] is a Python integer holding the address of the underlying data. The unsafe_get_as_pointer() method constructs an UnsafePointer to this address.\nWorking with C/C++ pointers\n\nIf you call a C/C++ function that returns a pointer using the external_call function, you can specify the return type as an UnsafePointer, and Mojo will handle the type conversion for you.\n\nfrom sys.ffi import external_call\n\ndef get_foreign_pointer() -> UnsafePointer[Int]:\n ptr = external_call[\n \"my_c_function\", # external function name\n UnsafePointer[Int] # return type\n ]()\n return ptr\n\nConverting data: bitcasting and byte order\n\nBitcasting a pointer returns a new pointer that has the same memory location, but a new data type. This can be useful if you need to access different types of data from a single area of memory. This can happen when you're reading binary files, like image files, or receiving data over the network.\n\nThe following sample processes a format that consists of chunks of data, where each chunk contains a variable number of 32-bit integers. Each chunk begins with an 8-bit integer that identifies the number of values in the chunk.\n\n\ndef read_chunks(owned ptr: UnsafePointer[UInt8]) -> List[List[UInt32]]:\n chunks = List[List[UInt32]]()\n # A chunk size of 0 indicates the end of the data\n chunk_size = int(ptr[])\n while (chunk_size > 0):\n # Skip the 1 byte chunk_size and get a pointer to the first\n # UInt32 in the chunk\n ui32_ptr = (ptr + 1).bitcast[UInt32]()\n chunk = List[UInt32](capacity=chunk_size)\n for i in range(chunk_size):\n chunk.append(ui32_ptr[i])\n chunks.append(chunk)\n # Move our pointer to the next byte after the current chunk\n ptr += (1 + 4 * chunk_size)\n # Read the size of the next chunk\n chunk_size = int(ptr[])\n return chunks\n\nWhen dealing with data read in from a file or from the network, you may also need to deal with byte order. Most systems use little-endian byte order (also called least-signficicant byte, or LSB) where the least-significant byte in a multibyte value comes first. For example, the number 1001 can be represented in hexadecimal as 0x03E9, where E9 is the least-significant byte. Represented as a 16-bit little-endian integer, the two bytes are ordered E9 03. As a 32-bit integer, it would be represented as E9 03 00 00.\n\nBig-endian or most-significant byte (MSB) ordering is the opposite: in the 32-bit case, 00 00 03 E9. MSB ordering is frequently used in file formats and when transmitting data over the network. You can use the byte_swap() function to swap the byte order of a SIMD value from big-endian to little-endian or the reverse. For example, if the method above was reading big-endian data, you'd just need to change a single line:\n\nchunk.append(byte_swap(ui32_ptr[i]))\n\nWorking with SIMD vectors\n\nThe UnsafePointer type includes load() and store() methods for performing aligned loads and stores of scalar values. It also has methods supporting strided load/store and gather/scatter.\n\nStrided load loads values from memory into a SIMD vector using an offset (the \"stride\") between successive memory addresses. This can be useful for extracting rows or columns from tabular data, or for extracting individual values from structured data. For example, consider the data for an RGB image, where each pixel is made up of three 8-bit values, for red, green, and blue. If you want to access just the red values, you can use a strided load or store.\n\nFigure 4. Strided load\n\nThe following function uses the strided_load() and strided_store() methods to invert the red pixel values in an image, 8 values at a time. (Note that this function only handles images where the number of pixels is evenly divisible by eight.)\n\ndef invert_red_channel(ptr: UnsafePointer[UInt8], pixel_count: Int):\n # number of values loaded or stored at a time\n alias simd_width = 8\n # bytes per pixel, which is also the stride size\n bpp = 3\n for i in range(0, pixel_count * bpp, simd_width * bpp):\n red_values = ptr.offset(i).strided_load[width=simd_width](bpp)\n # Invert values and store them in their original locations\n ptr.offset(i).strided_store[width=simd_width](~red_values, bpp)\n\nThe gather() and scatter() methods let you load or store a set of values that are stored in arbitrary locations. You do this by passing in a SIMD vector of offsets to the current pointer. For example, when using gather(), the nth value in the vector is loaded from (pointer address) + offset[n].\nSafety\n\nUnsafe pointers are unsafe for several reasons:\n\n Memory management is up to the user. You need to manually allocate and free memory, and be aware of when other APIs are allocating or freeing memory for you.\n\n UnsafePointer values are nullable—that is, the pointer is not guaranteed to point to anything. And even when a pointer points to allocated memory, that memory may not be initialized.\n\n Mojo doesn't track lifetimes for the data pointed to by an UnsafePointer. When you use an UnsafePointer, managing memory and knowing when to destroy objects is your responsibility.\n\nUnsafePointer and Reference\n\nThe Reference type is essentially a safe pointer type. Like a pointer, you can derferences a Reference using the dereference operator, []. However, the Reference type has several differences from UnsafePointer which make it safer:\n\n A Reference is non-nullable. A reference always points to something.\n You can't allocate or free memory using a Reference—only point to an existing value.\n A Reference only refers to a single value. You can't do pointer arithmetic with a Reference.\n A Reference has an associated lifetime, which connects it back to an original, owned value. The lifetime ensures that the value won't be destroyed while the reference exists.\n\nThe Reference type shouldn't be confused with the immutable and mutable references used with the borrowed and inout argument conventions. Those references do not require explicit dereferencing, unlike a Reference or UnsafePointer.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/pointers",
"description": "Unsafe Pointers in Mojo"
}
]
}
]
},
{
"section": "Python",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Python Integration",
"description": "How to integrate and use Python within Mojo",
"page_count": 1
},
"content": "Python integration\n\nMojo is still in early development and many Python features are not yet implemented. You can't currently write everything in Mojo that you can write in Python. And Mojo doesn't have its own ecosystem of packages yet.\n\nTo help bridge this gap, Mojo lets you import Python modules, call Python functions, and interact with Python objects from Mojo code. The Python code runs in a standard Python interpreter (CPython), so your existing Python code doesn't need to change.\n\n### Create a Python environment\n\nTo successfully integrate Python code with your Mojo project, your environment must have a compatible Python runtime installed along with any additional Python packages that you want to use. Currently, you can create a compatible environment in a couple of ways:\n\n- **Using Magic**: We recommend using Magic, our package manager and virtual environment manager for MAX and Mojo projects. First, install Magic and create a new project like this:\n \n ```bash\n magic init my-mojo-project --format mojoproject\n ```\n\n Then, navigate to the project and install any dependencies, such as NumPy:\n\n ```bash\n cd my-mojo-project\n magic add \"numpy>=2.0\"\n ```\n\n- **Using Conda**: You can also add MAX and Mojo to a conda project by following the appropriate steps in the documentation.\n\n- **Migrating Conda to Magic**: If you want to convert an existing conda project to Magic, see the relevant guide in the documentation.\n\n### Import a Python module\n\nTo import a Python module in Mojo, use the `Python.import_module()` function. Here's an example of importing and using the NumPy package in Mojo:\n\n```mojo\nfrom python import Python\n\ndef main():\n # Equivalent to Python's `import numpy as np`\n np = Python.import_module(\"numpy\")\n\n # Use NumPy as if writing in Python\n array = np.array([1, 2, 3])\n print(array)\n```\n\nOutput:\n\n```\n[1 2 3]\n```\n\nSome key points to note:\n\n- The `import_module()` method returns a reference to the module as a `PythonObject` wrapper, allowing access to the module's functions, classes, and objects.\n- Mojo currently doesn't support importing individual functions or classes from Python modules; you must import the entire module.\n- You cannot use top-level code in Mojo, so all imports must be done within a function.\n- `import_module()` may raise exceptions (e.g., if the module isn't installed), so error handling is needed. Use `try/except` or add `raises` to the function signature when calling Python functions that might throw exceptions.\n\n### Import a local Python module\n\nTo import a local Python module, you can add the directory to the Python path using `Python.add_to_path()` and then import the module. Here's an example of how to import and use a local module in Mojo:\n\n#### Local Python module (`mypython.py`):\n\n```python\nimport numpy as np\n\ndef gen_random_values(size, base):\n # Generate a size x size array of random numbers between base and base+1\n random_array = np.random.rand(size, size)\n return random_array + base\n```\n\n#### Mojo file (`main.mojo`):\n\n```mojo\nfrom python import Python\n\ndef main():\n Python.add_to_path(\"path/to/module\")\n mypython = Python.import_module(\"mypython\")\n\n values = mypython.gen_random_values(2, 3)\n print(values)\n```\n\nYou can add the current directory to the path using `Python.add_to_path(\".\")` if the module is in the same directory.\n\n### Call Mojo from Python\n\nAt the moment, you can call Python from Mojo, but Mojo cannot be called from Python. This limitation presents challenges when using some Python frameworks that rely on callbacks or event loops (like UI libraries). Since you can't pass Mojo functions as callbacks to Python modules, some frameworks may not work as expected.\n\nFor example, the typical pattern for a Python UI library like **Tkinter** involves creating a main window, setting up event-driven callbacks, and calling `mainloop()` to handle events. This doesn't work with Mojo because Python can't call back into Mojo.\n\n### Polling for updates in Python (Tkinter example)\n\nInstead of using Python's event loop, you can have Mojo control the flow by polling for updates. Here's an example where Mojo drives a Tkinter UI from Python:\n\n#### Python module (`myapp.py`):\n\n```python\nimport tkinter as tk\n\nclass App:\n def __init__(self):\n self._root = tk.Tk()\n self.clicked = False\n\n def click(self):\n self.clicked = True\n\n def create_button(self, button_text: str):\n button = tk.Button(\n master=self._root,\n text=button_text,\n command=self.click\n )\n button.place(relx=0.5, rely=0.5, anchor=tk.CENTER)\n\n def create(self, res: str):\n self._root.geometry(res)\n self.create_button(\"Hello Mojo!\")\n\n def update(self):\n self._root.update()\n```\n\n#### Mojo file (`main.mojo`):\n\n```mojo\nfrom python import Python\n\ndef button_clicked():\n print(\"Hi from a Mojo🔥 fn!\")\n\n\ndef main():\n Python.add_to_path(\".\")\n app = Python.import_module(\"myapp\").App()\n app.create(\"800x600\")\n\n while True:\n app.update()\n if app.clicked:\n button_clicked()\n app.clicked = False\n```\n\nIn this example, the Python module defines a simple Tkinter app with a button. Mojo handles the event loop by calling the `update()` method in a loop, checking if the button was clicked. When the button is clicked, it runs the `button_clicked()` Mojo function.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/python",
"description": "Python Integration in Mojo"
}
]
},
{
"document_id": "2",
"metadata": {
"title": "Python Types",
"description": "How to use Python Types in Mojo",
"page_count": 1
},
"content": "Python types\n\nWhen calling Python methods, Mojo needs to convert back and forth between native Python objects and native Mojo objects. Most of these conversions happen automatically, but there are cases where Mojo doesn't handle conversions yet, requiring explicit conversion or method calls.\n\n### Mojo types in Python\n\nMojo primitive types can be implicitly converted into Python objects. Supported types include lists, tuples, integers, floats, booleans, and strings.\n\nFor example, with this Python function that prints Python types:\n\n```python\n%%python\ndef type_printer(value):\n print(type(value))\n```\n\nYou can pass Mojo types to this function, and they will be interpreted as Python types:\n\n```mojo\ntype_printer(4)\ntype_printer(3.14)\ntype_printer((\"Mojo\", True))\n```\n\nOutput:\n\n```\n<class 'int'>\n<class 'float'>\n<class 'tuple'>\n```\n\nNote: This example uses Jupyter notebook cells, where `%%python` is required for Python code. In other environments, you can adjust accordingly.\n\n### Python types in Mojo\n\nPython objects can be used within Mojo. Mojo's native types like `Dict` and `List` don’t support heterogeneous collections, but you can use Python’s `dict()` or `list()` instead.\n\nFor example, to create a Python dictionary in Mojo:\n\n```mojo\nfrom python import Python\n\ndef use_dict():\n var dictionary = Python.dict()\n dictionary[\"item_name\"] = \"whizbang\"\n dictionary[\"price\"] = 11.75\n dictionary[\"inventory\"] = 100\n print(dictionary)\n```\n\n### Mojo wrapper objects\n\nWhen using Python objects in Mojo, they are wrapped in the `PythonObject` wrapper. This object exposes common dunder (double underscore) methods like `__getitem__()` and `__getattr__()`.\n\nYou can create a `PythonObject` from a Mojo literal:\n\n```mojo\nfrom python import PythonObject\nvar py_list: PythonObject = [1, 2, 3, 4]\n```\n\nYou can interact with it like a normal Python list:\n\n```mojo\nvar n = py_list[2]\npy_list.append(5)\n```\n\nFor types without a direct Mojo literal equivalent, use `Python.evaluate()`. For example, to create a Python set:\n\n```mojo\ndef use_py_set():\n var py_set = Python.evaluate('set([2, 3, 5, 7, 11])')\n var num_items = len(py_set)\n print(num_items, \" items in set.\") # prints \"5 items in set\"\n print(py_set.__contains__(6)) # prints \"False\"\n```\n\nNote: Currently, you need to call `__contains__()` directly instead of using `in` because of how `PythonObject` works.\n\nSome Mojo APIs handle `PythonObject` natively, but other times, explicit conversion is necessary. Currently, `PythonObject` conforms to traits like `Intable`, `Stringable`, and `Boolable`, allowing conversions using `int()`, `str()`, `bool()`, and `PythonObject.to_float64()` for floats.\n\n```mojo\nvar i: Int = int(py_int)\nvar s: String = str(py_string)\nvar b: Bool = bool(py_bool)\nvar f: Float64 = py_float.to_float64()\n```\n\n### Comparing Python types in Mojo\n\nIn conditionals, Python values like `False` and `None` behave as expected in Mojo. To check the type of a Python object, use `Python.type()`. To compare identities of Python objects, use `Python.is_type()` (similar to Python’s `is` operator).\n\n```mojo\ndef python_types():\n from python import Python\n from python import PythonObject\n\n var value1: PythonObject = 3.7\n var value2 = Python.evaluate(\"10/3\")\n var float_type = Python.evaluate(\"float\")\n\n print(Python.type(value1)) # <class 'float'>\n print(Python.is_type(Python.type(value1), Python.type(value2))) # True\n print(Python.is_type(Python.type(value1), float_type)) # True\n print(Python.is_type(Python.type(value1), Python.none())) # False\n```\n\nNote: The `Python.is_type()` method is currently misleadingly named, as it compares object identity rather than types.",
"links": [
{
"url": "https://docs.modular.com/mojo/manual/python/types",
"description": "Python Types in Mojo"
}
]
}
]
},
{
"section": "Testing",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Mojo Testing",
"description": "Writing test in Mojo",
"page_count": 1
},
"content": "Testing\n\nMojo includes a framework for writing and executing unit tests, as well as testing code examples in API documentation (docstrings). The framework comprises assertion functions in the Mojo standard library and a command line tool (`mojo test`) for running tests.\n\n### Get started\n\nHere’s how to get started with a simple example.\n\n#### 1. Write tests\n\nFirst, create a file named `test_quickstart.mojo` with the following code:\n\n```mojo\n# Content of test_quickstart.mojo\nfrom testing import assert_equal\n\ndef inc(n: Int) -> Int:\n return n + 1\n\ndef test_inc_zero():\n # This test contains an intentional error to demonstrate a failed test.\n assert_equal(inc(0), 0)\n\ndef test_inc_one():\n assert_equal(inc(1), 2)\n```\n\nIn this example, the `inc()` function is the target, and the functions prefixed with `test_` are the test cases. A test fails if it raises an error; otherwise, it passes. Here, the `assert_equal()` function is used to check that two values are equal.\n\nNote: `test_inc_zero()` has an intentional error to demonstrate a failed test.\n\n#### 2. Execute tests\n\nNext, in the directory containing the file, run this command:\n\n```bash\nmojo test test_quickstart.mojo\n```\n\nYou should see output like the following:\n\n```bash\nTesting Time: 1.193s\n\nTotal Discovered Tests: 2\n\nPassed : 1 (50.00%)\nFailed : 1 (50.00%)\nSkipped: 0 (0.00%)\n\n******************** Failure: 'ROOT_DIR/test_quickstart.mojo::test_inc_zero()' ********************\n\nUnhandled exception caught during execution\n\nError: At ROOT_DIR/test_quickstart.mojo:8:17: AssertionError: `left == right` comparison failed:\n left: 1\n right: 0\n```\n\nThis output gives a summary of test results and details of any failures.\n\n### The testing module\n\nThe Mojo standard library provides several assertion functions for writing tests:\n\n- `assert_true()`: Asserts that a value is `True`.\n- `assert_false()`: Asserts that a value is `False`.\n- `assert_equal()`: Asserts that two values are equal.\n- `assert_not_equal()`: Asserts that two values are not equal.\n- `assert_almost_equal()`: Asserts that two floating-point values are equal within a tolerance.\n\nExample:\n\n```mojo\nfrom testing import *\nassert_true(False)\n```\n\nThis raises an error:\n\n```bash\nError: AssertionError: condition was unexpectedly False\n```\n\nYou can provide a custom error message using the `msg` argument:\n\n```mojo\nassert_true(False, msg=\"paradoxes are not allowed\")\n```\n\nFor floating-point comparisons, use `assert_almost_equal()` to specify a tolerance:\n\n```mojo\nresult = 10 / 3\nassert_almost_equal(result, 3.33, atol=0.001, msg=\"close but no cigar\")\n```\n\nYou can also use the `assert_raises()` context manager to ensure that an error is raised:\n\n```mojo\ndef inc(n: Int) -> Int:\n if n == Int.MAX:\n raise Error(\"inc overflow\")\n return n + 1\n\nwith assert_raises():\n _ = inc(Int.MAX)\n```\n\nThis test passes because the error is raised.\n\nYou can check for specific error messages using the `contains` argument:\n\n```mojo\nwith assert_raises(contains=\"required\"):\n raise Error(\"missing required argument\")\n```\n\n### Writing unit tests\n\nMojo unit tests follow these conventions:\n\n- The test function name starts with `test_`.\n- It accepts no arguments.\n- It returns `None` or `object`.\n- It raises an error to indicate test failure.\n\nTests are typically placed in files prefixed or suffixed with `test`. For example:\n\n```mojo\n# File: test_my_target_module.mojo\nfrom my_target_module import convert_input, validate_input\nfrom testing import assert_equal, assert_false, assert_raises, assert_true\n\ndef test_validate_input():\n assert_true(validate_input(\"good\"))\n assert_false(validate_input(\"bad\"))\n\ndef test_convert_input():\n assert_equal(convert_input(\"input1\"), \"output1\")\n assert_equal(convert_input(\"input2\"), \"output2\")\n\ndef test_convert_input_error():\n with assert_raises():\n _ = convert_input(\"garbage\")\n```\n\n### The `mojo test` command\n\nMojo’s CLI includes the `mojo test` command for running tests or collecting lists of tests.\n\n#### Running tests\n\nYou can run tests by specifying:\n\n- A test ID (e.g., a single test function).\n- A file to run all tests in the file.\n- A directory to run all tests in that directory.\n\nExample commands:\n\n```bash\nmojo test -I src test\nmojo test -I src test/my_math/test_dec.mojo\nmojo test -I src 'test/my_math/test_dec.mojo::test_dec_valid()'\n```\n\n#### Collecting a list of tests\n\nTo collect tests, use the `--collect-only` (`--co`) option:\n\n```bash\nmojo test --co test\n```\n\nYou can also format the output in JSON using the `--diagnostic-format json` option:\n\n```bash\nmojo test --diagnostic-format json test_quickstart.mojo\n```\n\n### Writing API documentation tests\n\nMojo allows you to test code examples in docstrings.\n\n- Fenced code blocks marked with ```mojo are treated as executable tests.\n- Code blocks with standard triple backticks ``` are display-only and not executed.\n\nHere’s an example of an executable code block in a docstring:\n\n```mojo\n\"\"\" Executable code block example.\n\n```mojo\nfrom testing import assert_equal\nb = 2\nassert_equal(b, 2)\n```\n\"\"\"\n```\n\nIf you want a line to be executed but not displayed in the documentation, prefix it with `%#`.\n\n### Documentation test suites and scoping\n\nMojo treats each docstring as a separate test suite. Executable code blocks in the same docstring share the same scope, meaning variables from one block can be accessed in the next block.\n\nExample:\n\n```mojo\n\"\"\" Stateful example.\n\n```mojo\na = 1\n```\n\n```mojo\na += 1\n```\n\"\"\"\n```\n\nHowever, test suite scopes do not nest. Variables in a module’s test suite are not accessible in a function’s test suite within that module.\n\n### Documentation test identifiers\n\nThe format for a documentation test identifier is `<path>@<test-suite>::<test>`.\n\nFor example, a project might contain tests like this:\n\n```bash\n<ROOT_DIR/src/my_math>\n <ROOT_DIR/src/my_math/__init__.mojo>\n <ROOT_DIR/src/my_math/__init__.mojo@__doc__>\n <ROOT_DIR/src/my_math/__init__.mojo@__doc__::0>\n```\n <ROOT_DIR/src/my_math/__init__.mojo@__doc__::1>\n <ROOT_DIR/src/my_math/utils.mojo>\n <ROOT_DIR/src/my_math/utils.mojo@__doc__>\n <ROOT_DIR/src/my_math/utils.mojo@__doc__::0>\n <ROOT_DIR/src/my_math/utils.mojo@inc(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__>\n <ROOT_DIR/src/my_math/utils.mojo@inc(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__::0>\n <ROOT_DIR/src/my_math/utils.mojo@inc(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__::1>\n <ROOT_DIR/src/my_math/utils.mojo@dec(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__>\n <ROOT_DIR/src/my_math/utils.mojo@dec(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__::0>\n <ROOT_DIR/src/my_math/utils.mojo@dec(stdlib\\3A\\3Abuiltin\\3A\\3Aint\\3A\\3AInt).__doc__::1>\n\nSeveral different test suites appear in this result:\n\n| Test suite scope | File | Test suite name |\n|--------------------|-------------------------------------|-----------------|\n| Package | `src/my_math/__init__.mojo` | `__doc__` |\n| Module | `src/my_math/utils.mojo` | `__doc__` |\n| Function | `src/my_math/utils.mojo@inc()` | `__doc__` |\n\nWithin a specific test suite, tests are numbered sequentially in the order they appear in the docstring, starting with 0. This numbering scheme helps track and identify tests when collecting and running them with `mojo test`.",
"links": [
{
"url": "https://docs.modular.com/mojo/tools/testing",
"description": "Mojo Testing"
}
]
}
]
},
{
"section": "Code and Scripts",
"data": [
{
"document_id": "1",
"metadata": {
"title": "Hello Mojo 🔥!",
"description": "A simple hello world program in Mojo"
},
"content": {
"code": "```mojo\ndef main():\n print('Hello Mojo 🔥!')\nfor x in range(9, 0, -3):\n print(x)\n```"
}
},
{
"document_id": "2",
"metadata": {
"title": "Simple Interop",
"description": "A simple interop example in Mojo"
},
"content": {
"code": "```mojo\nfrom python import Python\n\ndef main():\n print('Hello Mojo 🔥!')\nfor x in range(9, 0, -3):\n print(x)\nPython.add_to_path('.')\nPython.add_to_path('./examples')\nvar test_module = Python.import_module('simple_interop')\ntest_module.test_interop_func()\n```"
}
},
{
"document_id": "3",
"metadata": {
"title": "Device Info in Mojo",
"description": "A simple script to check device info within Mojo"
},
"content": {
"code":"```mojo\nfrom sys import (has_avx, has_avx2, has_avx512f, has_intel_amx, has_neon, has_sse4, has_vnni, is_apple_m1, is_apple_m2, is_apple_m3, num_logical_cores, num_physical_cores, os_is_linux, os_is_macos, os_is_windows)\nfrom sys.info import _current_arch, _current_target, _triple_attr\n\ndef main():\n var os = \"\"\n if os_is_linux():\n os = \"linux\"\n elif os_is_macos():\n os = \"macOS\"\n else:\n os = \"windows\"\n var cpu = String(_current_arch())\n var arch = String(_triple_attr())\n var cpu_features = String(\"\")\n if has_sse4():\n cpu_features += \" sse4\"\n if has_avx():\n cpu_features += \" avx\"\n if has_avx2():\n cpu_features += \" avx2\"\n if has_avx512f():\n cpu_features += \" avx512f\"\n if has_vnni():\n if has_avx512f():\n cpu_features += \" avx512_vnni\"\n else:\n cpu_features += \" avx_vnni\"\n if has_intel_amx():\n cpu_features += \" intel_amx\"\n if has_neon():\n cpu_features += \" neon\"\n if is_apple_m1():\n cpu_features += \" Apple M1\"\n if is_apple_m2():\n cpu_features += \" Apple M2\"\n if is_apple_m3():\n cpu_features += \" Apple M3\"\n\n print(\"System information: \")\n print(\" OS : \", os)\n print(\" CPU : \", cpu)\n print(\" Arch : \", arch)\n print(\" Physical Cores : \", num_physical_cores())\n print(\" Logical Cores : \", num_logical_cores())\n print(\" CPU Features :\", cpu_features)\n```"
}
},
{
"document_id": "4",
"metadata": {
"title": "Creating a Mandlebrot set in Mojo",
"description": "Building a Mandlebrot set"
},
"content": {
"code":"```mojo\nfrom math import iota\nfrom sys import num_physical_cores, simdwidthof\n\nimport benchmark\nfrom algorithm import parallelize, vectorize\nfrom complex import ComplexFloat64, ComplexSIMD\n\nalias float_type = DType.float32\nalias int_type = DType.int32\nalias simd_width = 2 * simdwidthof\n var y = SIMD \n var y2 = SIMD \n var iters = SIMD \n var t: SIMD[DType.bool, simd_width] = True\n\n for _ in range(MAX_ITERS):\n if not any(t):\n break\n y2 = y * y\n y = x.fma(y + y, cy)\n t = x.fma(x, y2) <= 4\n x = x.fma(x, cx - y2)\n iters = t.select(iters + 1, iters)\n return iters\n\n\nfn main() raises:\n var matrix = Matrix[int_type, rows, cols]()\n\n @parameter\n fn worker(row: Int):\n alias scale_x = (max_x - min_x) / cols\n alias scale_y = (max_y - min_y) / rows\n\n @parameter\n fn compute_vector[simd_width: Int](col: Int):\n \"\"\"Each time we operate on a `simd_width` vector of pixels.\"\"\"\n var cx = min_x + (col + iota[float_type, simd_width]()) * scale_x\n var cy = min_y + row * SIMD[float_type, simd_width](scale_y)\n var c = ComplexSIMD[float_type, simd_width](cx, cy)\n matrix.store(row, col, mandelbrot_kernel_SIMD(c))\n\n # Vectorize the call to compute_vector with a chunk of pixels.\n vectorize[compute_vector, simd_width, size=cols]()\n\n @parameter\n fn bench():\n for row in range(rows):\n worker(row)\n\n @parameter\n fn bench_parallel():\n parallelize[worker](rows, rows)\n\n print(\"Number of physical cores:\", num_physical_cores())\n\n var vectorized = benchmark.run[bench]().mean(unit)\n print(\"Vectorized:\", vectorized, unit)\n var parallelized = benchmark.run[bench_parallel]().mean(unit)\n print(\"Parallelized:\", parallelized, unit)\n\n # CHECK: Parallel speedup\n print(\"Parallel speedup:\", vectorized / parallelized)\n\n matrix.data.free()\n```"
}
},
{
"document_id": "5",
"metadata": {
"title": "Matmul in Mojo",
"description": "A script demonstrating matrix multiplication in Mojo"
},
"content": {
"code":"```mojo\nfrom os.env import getenv\nfrom random import rand\nfrom sys import info\nfrom sys import simdwidthof\n\nimport benchmark\nfrom algorithm import Static2DTileUnitFunc as Tile2DFunc\nfrom algorithm import parallelize, vectorize\nfrom memory import memset_zero, stack_allocation\nfrom python import Python, PythonObject\n\nalias M = 512\nalias N = 4096\nalias K = 512\nalias type = DType.float32\nalias nelts = get_simd_width()\n\nfn get_simd_width() -> Int:\n @parameter\n if info.is_apple_silicon():\n return 4 * simdwidthof[type]()\n else:\n return 2 * simdwidthof[type]()\n\nalias tile_n = 64\nalias tile_k = 4\n\nstruct Matrix[rows: Int, cols: Int]:\n var data: UnsafePointer[Scalar[type]]\n\n fn __init__(inout self):\n self.data = UnsafePointer[Scalar[type]].alloc(rows * cols)\n memset_zero(self.data, rows * cols)\n\n fn __init__(inout self, data: UnsafePointer[Scalar[type]]):\n self.data = data\n\n @staticmethod\n fn rand() -> Self:\n var data = UnsafePointer[Scalar[type]].alloc(rows * cols)\n rand(data, rows * cols)\n return Self(data)\n\n fn __getitem__(self, y: Int, x: Int) -> Scalar[type]:\n return self.load(y, x)\n\n fn __setitem__(inout self, y: Int, x: Int, val: Scalar[type]):\n self.store(y, x, val)\n\n fn load[nelts: Int = 1](self, y: Int, x: Int) -> SIMD[type, nelts]:\n return self.data.load[width=nelts](y * self.cols + x)\n\n fn store[nelts: Int = 1](self, y: Int, x: Int, val: SIMD[type, nelts]):\n self.data.store[width=nelts](y * self.cols + x, val)\n\n\ndef run_matmul_python() -> Float64:\n var pymatmul: PythonObject = Python.import_module(\"pymatmul\")\n var py = Python.import_module(\"builtins\")\n var gflops = pymatmul.benchmark_matmul_python(128, 128, 128).to_float64()\n py.print(py.str(\"{:<18}{:>8.3f} GFLOPS\").format(\"Python:\", gflops))\n return gflops\n\n\ndef run_matmul_numpy() -> Float64:\n var pymatmul: PythonObject = Python.import_module(\"pymatmul\")\n var py = Python.import_module(\"builtins\")\n var gflops = pymatmul.benchmark_matmul_numpy(M, N, K).to_float64()\n py.print(py.str(\"{:<18}{:>8.3f} GFLOPS\").format(\"Numpy:\", gflops))\n return gflops\n\nfn matmul_naive(inout C: Matrix, A: Matrix, B: Matrix):\n for m in range(C.rows):\n for k in range(A.cols):\n for n in range(C.cols):\n C[m, n] += A[m, k] * B[k, n]\n\n\nfn matmul_vectorized(inout C: Matrix, A: Matrix, B: Matrix):\n for m in range(C.rows):\n for k in range(A.cols):\n @parameter\n fn dot[nelts: Int](n: Int):\n C.store[nelts](m, n, C.load[nelts](m, n) + A[m, k] * B.load[nelts](k, n))\n vectorize[dot, nelts, size = C.cols]()\n\n\nfn matmul_parallelized(inout C: Matrix, A: Matrix, B: Matrix):\n var num_workers = C.rows\n @parameter\n fn calc_row(m: Int):\n for k in range(A.cols):\n @parameter\n fn dot[nelts: Int](n: Int):\n C.store[nelts](m, n, C.load[nelts](m, n) + A[m, k] * B.load[nelts](k, n))\n vectorize[dot, nelts, size = C.cols]()\n parallelize[calc_row](C.rows, num_workers)\n\n\nfn tile[tiled_fn: Tile2DFunc, tile_x: Int, tile_y: Int](end_x: Int, end_y: Int):\n for y in range(0, end_y, tile_y):\n for x in range(0, end_x, tile_x):\n tiled_fn[tile_x, tile_y](x, y)\n\n\nfn matmul_tiled(inout C: Matrix, A: Matrix, B: Matrix):\n var num_workers = C.rows\n @parameter\n fn calc_row(m: Int):\n @parameter\n fn calc_tile[tile_x: Int, tile_y: Int](x: Int, y: Int):\n for k in range(y, y + tile_y):\n @parameter\n fn dot[nelts: Int](n: Int):\n C.store(m, n + x, C.load[nelts](m, n + x) + A[m, k] * B.load[nelts](k, n + x))\n vectorize[dot, nelts, size=tile_x]()\n tile[calc_tile, tile_n, tile_k](C.cols, B.rows)\n parallelize[calc_row](C.rows, num_workers)\n\n\nfn matmul_unrolled[mode: Int](inout C: Matrix, A: Matrix, B: Matrix):\n var num_workers: Int\n if mode == 1:\n num_workers = info.num_physical_cores()\n elif mode == 2:\n num_workers = info.num_logical_cores()\n elif mode == 3:\n num_workers = info.num_performance_cores()\n else:\n num_workers = C.rows\n @parameter\n fn calc_row(m: Int):\n @parameter\n fn calc_tile[tile_x: Int, tile_y: Int](x: Int, y: Int):\n @parameter\n for _k in range(tile_y):\n var k = _k + y\n @parameter\n fn dot[nelts: Int](n: Int):\n C.store(m, n + x, C.load[nelts](m, n + x) + A[m, k] * B.load[nelts](k, n + x))\n vectorize[dot, nelts, size=tile_x, unroll_factor = tile_x // nelts]()\n tile[calc_tile, tile_n, tile_k](C.cols, B.rows)\n parallelize[calc_row](C.rows, num_workers)\n\n\nfn tile_parallel[tiled_fn: Tile2DFunc, tile_m: Int, tile_n: Int](end_m: Int, end_n: Int,):\n @parameter\n fn row(mo: Int):\n var m = tile_m * mo\n for n in range(0, end_n, tile_n):\n tiled_fn[tile_m, tile_n](m, n)\n parallelize[row](end_m // tile_m, M)\n\n\nfn matmul_reordered(inout C: Matrix, A: Matrix, B: Matrix):\n alias tile_m = 32\n alias tile_n = 32\n alias tile_k = max(4, K // 256)\n constrained[M % tile_m == 0, \"M must be a multiple of tile_m\"]()\n constrained[N % tile_n == 0, \"N must be a multiple of tile_n\"]()\n constrained[K % tile_k == 0, \"K must be a multiple of tile_k\"]()\n @parameter\n fn calc_tile[tile_m: Int, tile_n: Int](mo: Int, no: Int):\n var accumulator = Matrix[tile_m, tile_n](stack_allocation[tile_m * tile_n, type]())\n memset_zero(accumulator.data, tile_m * tile_n)\n for ko in range(0, A.cols, tile_k):\n @parameter\n fn calc_tile_row[](m: Int):\n @parameter\n for k in range(tile_k):\n @parameter\n fn dot[nelts: Int](n: Int):\n accumulator.store(m, n, accumulator.load[nelts](m, n) + A[mo + m, ko + k] * B.load[nelts](ko + k, no + n))\n vectorize[dot, nelts, size=tile_n, unroll_factor = tile_n // nelts]()\n for m in range(tile_m):\n calc_tile_row(m)\n for m in range(tile_m):\n for n in range(tile_n):\n C[mo + m, no + n] = accumulator[m, n]\n tile_parallel[calc_tile, tile_m, tile_n](C.rows, C.cols)\n\n\n@always_inline\nfn bench[func: fn (inout Matrix, Matrix, Matrix) -> None, name: StringLiteral](base_gflops: Float64, np_gflops: Float64) raises:\n var A = Matrix[M, K].rand()\n var B = Matrix[K, N].rand()\n var C = Matrix[M, N]()\n @always_inline\n @parameter\n fn test_fn():\n _ = func(C, A, B)\n var secs = benchmark.run[test_fn](max_runtime_secs=0.5).mean()\n A.data.free()\n B.data.free()\n C.data.free()\n var gflops = ((2 * M * N * K) / secs) / 1e9\n var speedup: Float64 = gflops / base_gflops\n var numpy_speedup: Float64 = gflops / np_gflops\n var py = Python.import_module(\"builtins\")\n _ = py.print(py.str(\"{:<18}{:>8.3f} GFLOPS {:>9.2f}x Python {:.2f}x Numpy\").format(name, gflops, speedup, numpy_speedup))\n\n\n@always_inline\nfn test_matrix_equal[func: fn (inout Matrix, Matrix, Matrix) -> None](C: Matrix, A: Matrix, B: Matrix) raises -> Bool:\n var result = Matrix[M, N]()\n _ = func(result, A, B)\n for i in range(C.rows):\n for j in range(C.cols):\n if C[i, j] != result[i, j]:\n return False\n return True\n\n\ndef test_all():\n var A = Matrix[M, K].rand()\n var B = Matrix[K, N].rand()\n var C = Matrix[M, N]()\n matmul_naive(C, A, B)\n if not test_matrix_equal[matmul_vectorized](C, A, B):\n raise Error(\"Vectorize output does not match naive implementation\")\n if not test_matrix_equal[matmul_parallelized](C, A, B):\n raise Error(\"Parallelize output does not match naive implementation\")\n if not test_matrix_equal[matmul_tiled](C, A, B):\n raise Error(\"Tiled output does not match naive implementation\")\n if not test_matrix_equal[matmul_unrolled[0]](C, A, B):\n raise Error(\"Unroll output does not match naive implementation\")\n if not test_matrix_equal[matmul_unrolled[1]](C, A, B):\n raise Error(\"Unroll/physical cores does not match naive implementation\")\n if not test_matrix_equal[matmul_unrolled[2]](C, A, B):\n raise Error(\"Unroll/logical cores does not match naive implementation\")\n if not test_matrix_equal[matmul_unrolled[3]](C, A, B):\n raise Error(\"Unroll/perf cores does not match naive implementation\")\n if not test_matrix_equal[matmul_reordered](C, A, B):\n raise Error(\"Loop reorder output does not match naive implementation\")\n A.data.free()\n B.data.free()\n C.data.free()\n\n\ndef main():\n constrained[N % tile_n == 0, \"N must be a multiple of tile_n\"]()\n constrained[K % tile_k == 0, \"K must be a multiple of tile_k\"]()\n print(\"Problem Size (M N K):\", M, N, K)\n test_all()\n print(\"CPU Results\\n\")\n var py_gflops = run_matmul_python()\n var np_gflops = run_matmul_numpy()\n if not getenv(\"CI\"):\n bench[matmul_naive, \"Naive:\"](py_gflops, np_gflops)\n bench[matmul_vectorized, \"Vectorized:\"](py_gflops, np_gflops)\n bench[matmul_parallelized, \"Parallelized:\"](py_gflops, np_gflops)\n bench[matmul_tiled, \"Tiled:\"](py_gflops, np_gflops)\n bench[matmul_unrolled[0], \"Unrolled:\"](py_gflops, np_gflops)\n bench[matmul_unrolled[1], \"Physical Cores:\"](py_gflops, np_gflops)\n bench[matmul_unrolled[2], \"Logical Cores:\"](py_gflops, np_gflops)\n bench[matmul_unrolled[3], \"Performance Cores:\"](py_gflops, np_gflops)\n bench[matmul_reordered, \"Reordered:\"](py_gflops, np_gflops)\n```"
}
},
{
"document_id": "6",
"metadata": {
"title": "N-Body Simulation in Mojo",
"description": "Creating and interacting with a N-Body simulation"
},
"content": {
"code":"```mojo\nfrom collections import List\nfrom math import sqrt\nfrom benchmark import keep, run\nfrom testing import assert_almost_equal\nalias PI = 3.141592653589793\nalias SOLAR_MASS = 4 * PI * PI\nalias DAYS_PER_YEAR = 365.24\n\n@value\nstruct Planet:\n var pos: SIMD[DType.float64, 4]\n var velocity: SIMD[DType.float64, 4]\n var mass: Float64\n\n fn __init__(inout self, pos: SIMD[DType.float64, 4], velocity: SIMD[DType.float64, 4], mass: Float64):\n self.pos = pos\n self.velocity = velocity\n self.mass = mass\n\n\nalias Sun = Planet(0, 0, SOLAR_MASS)\nalias Jupiter = Planet(SIMD[DType.float64, 4](4.84143144246472090e00, -1.16032004402742839e00, -1.03622044471123109e-01, 0), SIMD[DType.float64, 4](1.66007664274403694e-03 * DAYS_PER_YEAR, 7.69901118419740425e-03 * DAYS_PER_YEAR, -6.90460016972063023e-05 * DAYS_PER_YEAR, 0), 9.54791938424326609e-04 * SOLAR_MASS)\nalias Saturn = Planet(SIMD[DType.float64, 4](8.34336671824457987e00, 4.12479856412430479e00, -4.03523417114321381e-01, 0), SIMD[DType.float64, 4](-2.76742510726862411e-03 * DAYS_PER_YEAR, 4.99852801234917238e-03 * DAYS_PER_YEAR, 2.30417297573763929e-05 * DAYS_PER_YEAR, 0), 2.85885980666130812e-04 * SOLAR_MASS)\nalias Uranus = Planet(SIMD[DType.float64, 4](1.28943695621391310e01, -1.51111514016986312e01, -2.23307578892655734e-01, 0), SIMD[DType.float64, 4](2.96460137564761618e-03 * DAYS_PER_YEAR, 2.37847173959480950e-03 * DAYS_PER_YEAR, -2.96589568540237556e-05 * DAYS_PER_YEAR, 0), 4.36624404335156298e-05 * SOLAR_MASS)\nalias Neptune = Planet(SIMD[DType.float64, 4](1.53796971148509165e01, -2.59193146099879641e01, 1.79258772950371181e-01, 0), SIMD[DType.float64, 4](2.68067772490389322e-03 * DAYS_PER_YEAR, 1.62824170038242295e-03 * DAYS_PER_YEAR, -9.51592254519715870e-05 * DAYS_PER_YEAR, 0), 5.15138902046611451e-05 * SOLAR_MASS)\nalias INITIAL_SYSTEM = List[Planet](Sun, Jupiter, Saturn, Uranus, Neptune)\n\n@always_inline\nfn offset_momentum(inout bodies: List[Planet]):\n var p = SIMD[DType.float64, 4]()\n for body in bodies:\n p += body[].velocity * body[].mass\n var body = bodies[0]\n body.velocity = -p / SOLAR_MASS\n bodies[0] = body\n\n@always_inline\nfn advance(inout bodies: List[Planet], dt: Float64):\n for i in range(len(INITIAL_SYSTEM)):\n for j in range(len(INITIAL_SYSTEM) - i - 1):\n var body_i = bodies[i]\n var body_j = bodies[j + i + 1]\n var diff = body_i.pos - body_j.pos\n var diff_sqr = (diff * diff).reduce_add()\n var mag = dt / (diff_sqr * sqrt(diff_sqr))\n body_i.velocity -= diff * body_j.mass * mag\n body_j.velocity += diff * body_i.mass * mag\n bodies[i] = body_i\n bodies[j + i + 1] = body_j\n for body in bodies:\n body[].pos += dt * body[].velocity\n\n@always_inline\nfn energy(bodies: List[Planet]) -> Float64:\n var e: Float64 = 0\n for i in range(len(INITIAL_SYSTEM)):\n var body_i = bodies[i]\n e += (0.5 * body_i.mass * ((body_i.velocity * body_i.velocity).reduce_add()))\n for j in range(len(INITIAL_SYSTEM) - i - 1):\n var body_j = bodies[j + i + 1]\n var diff = body_i.pos - body_j.pos\n var distance = sqrt((diff * diff).reduce_add())\n e -= (body_i.mass * body_j.mass) / distance\n return e\n\ndef run_system():\n print(\"Starting nbody...\")\n var system = INITIAL_SYSTEM\n offset_momentum(system)\n print(\"Energy of System:\", energy(system))\n for i in range(50_000_000):\n advance(system, 0.01)\n var system_energy = energy(system)\n assert_almost_equal(system_energy, -0.1690599)\n print(\"Energy of System:\", system_energy)\n\ndef benchmark():\n fn benchmark_fn():\n var system = INITIAL_SYSTEM\n offset_momentum(system)\n keep(energy(system))\n for i in range(50_000_000):\n advance(system, 0.01)\n keep(energy(system))\n run[benchmark_fn](max_runtime_secs=0.5).print()\n\ndef main():\n run_system()\n```"
}
},
{
"document_id": "7",
"metadata": {
"title": "Reduce in Mojo",
"description": "Using reduce within Mojo"
},
"content": {
"code":"```mojo\n# This sample implements a simple reduction operation on a\n# large array of values to produce a single result.\n# Reductions and scans are common algorithm patterns in parallel computing.\n\nfrom random import rand\nfrom time import now\nfrom algorithm import sum\nfrom benchmark import Unit, benchmark, keep\nfrom buffer import Buffer\nfrom python import Python\n\n# Change these numbers to reduce on different sizes\nalias size_small: Int = 1 << 21\nalias size_large: Int = 1 << 27\n\n# Datatype for Tensor/Array\nalias type = DType.float32\nalias scalar = Scalar[type]\n\n\n# Use the https://en.wikipedia.org/wiki/Kahan_summation_algorithm\n# Simple summation of the array elements\nfn naive_reduce_sum[size: Int](buffer: Buffer[type, size]) -> scalar:\n var my_sum: scalar = 0\n var c: scalar = 0\n for i in range(buffer.size):\n var y = buffer[i] - c\n var t = my_sum + y\n c = (t - my_sum) - y\n my_sum = t\n return my_sum\n\nfn stdlib_reduce_sum[size: Int](array: Buffer[type, size]) -> scalar:\n var my_sum = sum(array)\n return my_sum\n\ndef pretty_print(name: String, elements: Int, time: Float64):\n py = Python.import_module(\"builtins\")\n py.print(\n py.str(\"{:<16} {:>11,} {:>8.2f}ms\").format(\n name + \" elements:\", elements, time\n )\n )\n\nfn bench[\n func: fn[size: Int] (buffer: Buffer[type, size]) -> scalar,\n size: Int,\n name: String,\n](buffer: Buffer[type, size]) raises:\n @parameter\n fn runner():\n var result = func[size](buffer)\n keep(result)\n\n var ms = benchmark.run[runner](max_runtime_secs=0.5).mean(Unit.ms)\n pretty_print(name, size, ms)\n\nfn main() raises:\n print(\n \"Sum all values in a small array and large array\\n\"\n \"Shows algorithm.sum from stdlib with much better performance\\n\"\n )\n # Allocate and randomize data, then create two buffers\n var ptr_small = UnsafePointer[Scalar[type]].alloc(size_small)\n var ptr_large = UnsafePointer[Scalar[type]].alloc(size_large)\n rand(ptr_small, size_small)\n rand(ptr_large, size_large)\n var buffer_small = Buffer[type, size_small](ptr_small)\n var buffer_large = Buffer[type, size_large](ptr_large)\n bench[naive_reduce_sum, size_small, \"naive\"](buffer_small)\n bench[naive_reduce_sum, size_large, \"naive\"](buffer_large)\n bench[stdlib_reduce_sum, size_small, \"stdlib\"](buffer_small)\n # CHECK: stdlib elements\n bench[stdlib_reduce_sum, size_large, \"stdlib\"](buffer_large)\n ptr_small.free()\n ptr_large.free()\n```"
}
}
]
}
]