value : V;
}
-init :: proc (use map: ^Map($K, $V), dv: V = ~~0, hash_count: i32 = 16) {
+init :: proc (use map: ^Map($K, $V), default: V = ~~0, hash_count: i32 = 16) {
array.init(^hashes, hash_count);
array.init(^entries, 4);
- default_value = dv;
+ default_value = default;
for i: 0 .. hash_count do array.push(^hashes, -1);
}
+// Looping over data structures is a very common operation done in all programming
+// practices. In fact, I'd argue 97% of all programming problems can be solved by
+// putting information into an array and looping over it. For this reason, for loops
+// in Onyx are extremely simple to use by design and should make programming very
+// enjoyable. But I digress, let's look at some examples.
+
#load "core/std/wasi"
use package core
main :: proc (args: [] cstr) {
+ // Currently, for loops can iterate over four kinds of data structures in Onyx:
+ // * Ranges
+ // * Fixed arrays
+ // * Slices
+ // * Dynamic arrays
+
+ // The syntax of for loops is very simple:
+ // for ^? <iteration variable>: <iterator> <block>
+
+ // For example, this will print out the numbers in the array literal:
+ for i: u32.[ 10, 20, 30, 40, 50 ] {
+ println(i);
+ }
+ print("\n\n");
+
+
+ // You may have noticed the options caret (^) in the definition of the for loop
+ // syntax. When a caret is placed before the iteration variable, the iteration
+ // variable will be a *pointer* to the data inside the iterator. This is useful
+ // for iterating over larger data structures that don't need to be copied for
+ // every iteration, or when you want to modify the elements of the iterator, as
+ // so:
+
+ primes := u32.[ 2, 3, 5, 7, 11, 13, 17 ];
+ for ^prime: primes {
+ *prime *= 2;
+ }
+
+ print("Doubled primes: ");
+ print_array(primes);
+
+ // Currently, there is not support for defining custom iterators for for-loops.
+ // At the moment, this pattern is the best for that purpose:
+ //
+ // while it := iterator_create(...); !iterator_done(^it) {
+ // defer iterator_next(^it);
+ // ...
+ // }
}
use package core
main :: proc (args: [] cstr) {
+ x := 10 + 3 * 5;
+
+ // The basic syntax of a switch statement:
+ switch x {
+ case 10 do println("x was 10.");
+
+ case 25 {
+ println("x was 25.");
+ println("Multiple statments go between '{}'.");
+ }
+
+ case #default {
+ println("Default case reached.");
+ }
+ }
+ println("\n");
+
+ // There are several semantic differences between Onyx switch statements and
+ // C/C++ switch statements. The most obvious one is that there is no implicit
+ // fallthrough to the next lexical case. This is more intuitive and less error
+ // prone. If you do with to fallthrough, the `fallthrough` keyword can be used
+ // as so:
+
+ switch x {
+ case 10 do println("x was 10.");
+
+ case 25 {
+ println("x was 25.");
+ println("Multiple statments go between '{}'.");
+ fallthrough; // Now we fallthrough
+ }
+
+ case #default {
+ println("Default case reached.");
+ }
+ }
+ println("\n");
+
+ // The other semantic different is that each case introduces a lexical block where
+ // local variables can be defined, and statements can be deferred. Take this
+ // interesting example:
+
+ switch 5 {
+ case 3 do println("This will never be reached.");
+
+ case 5 {
+ x := math.max(20, 50);
+ defer printf("x in case '5' is %i.\n", x);
+
+ if x >= 40 do fallthrough;
+
+ println("This statement will never be reached.");
+ }
+
+ case #default {
+ println("Default case reached.");
+ }
+ }
+ println("\n");
}
use package core
main :: proc (args: [] cstr) {
+ // Onyx does not have map type built into the language semantics,
+ // but using polymorphic structs and overloaded procedures, it does
+ // provide an 'any-to-any' hash map in it's core libraries.
+
+ // To use it, simply create one like so:
+ ages : map.Map(str, u32);
+ map.init(^ages, default=0, hash_count=16);
+ defer map.free(^ages);
+
+ // The defer statement ensures that the map memory will be freed
+ // when this procedure exits, no matter through which way. The
+ // 'default' argument is used to specify what value should be
+ // returned when the map does not contain the requested key. The
+ // hash_count is an implementation detail that will go away in the
+ // near future. It is the maximum number of chains in the hash table.
+
+ // To put an entry into the map, use the map.put procedure.
+ map.put(^ages, "Dwight", 32);
+ map.put(^ages, "Jim", 25);
+ map.put(^ages, "Pam", 24);
+
+ // To retrieve an entry's value, use the map.get procedure.
+ print_age :: proc (ages: ^map.Map(str, u32), name: str) {
+ age := map.get(ages, name);
+ printf("%s's age is %i.\n", name, age);
+ }
+
+ print_age(^ages, "Dwight");
+ print_age(^ages, "Jim");
+ print_age(^ages, "Pam");
+ print_age(^ages, "Michael");
+
+ // You may noticed if you ran this program that it prints Michael's
+ // age is 0. This is because there was entry for the key 'Michael',
+ // and we provided the default of '0'. To ensure that a key is in the
+ // map, use the map.has procedure
+
+ println(map.has(^ages, "Dwight"));
+ println(map.has(^ages, "Michael"));
+
+
+
+ // Not now nor ever will Onyx support an "interface" concept to say
+ // which types can do which things. One thing that Onyx does have
+ // however is explicit overloaded procedures. They are talked about
+ // more in 14_overloaded_procs.onyx. For our purposes right now, we
+ // just need to know that Map uses two overloaded procedures to
+ // achieve its implementation: map.hash_function, map.cmp_function.
+ // To make Map work with any new datatype you come up with, simply
+ // define an overload for map.hash_function and map.cmp_function.
+ // If you want to see what this looks like, take a look at
+ // tests/aoc-2020/day17.onyx in this repository.
}