-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Document arrays and loops #341
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,103 @@ | ||||||
--- | ||||||
title: Arrays | ||||||
--- | ||||||
|
||||||
An alternative to lists, arrays are fixed-length containers for ordered data. Individual elements can be swapped out for other elements, and individual elements can be retrieved quickly. | ||||||
|
||||||
## Creating and Using Arrays | ||||||
|
||||||
Like lists, arrays always contain elements of the same type, and attempting to mix element types will result in a compilation error. | ||||||
|
||||||
```grain | ||||||
let empty = [>] | ||||||
let numbers = [> 1, 2, 3] | ||||||
let strings = [> "foo", "bar", "baz"] | ||||||
``` | ||||||
|
||||||
Unlike lists, we can easily access elements at any (zero-based) index: | ||||||
|
||||||
```grain | ||||||
let strings = [> "foo", "bar", "baz"] | ||||||
|
||||||
print(strings[0]) // "foo" | ||||||
print(strings[1]) // "bar" | ||||||
print(strings[2]) // "baz" | ||||||
``` | ||||||
|
||||||
We can also use negative indexes to access elements from the end of the array: | ||||||
|
||||||
```grain | ||||||
let strings = [> "foo", "bar", "baz"] | ||||||
|
||||||
print(strings[-1]) // "baz" | ||||||
print(strings[-2]) // "bar" | ||||||
print(strings[-3]) // "foo" | ||||||
``` | ||||||
|
||||||
If we try to access an element beyond the length of the array, we'll get an `IndexOutOfBounds` error. | ||||||
|
||||||
## Updating Arrays | ||||||
|
||||||
One of the major benefits of an array is the ability to change the values it contains. We can update an array's values like so: | ||||||
|
||||||
```grain | ||||||
let strings = [> "foo", "bar", "baz"] | ||||||
|
||||||
print(strings) // [> "foo", "bar", "baz"] | ||||||
|
||||||
strings[1] = "qux" | ||||||
|
||||||
print(strings) // [> "foo", "qux", "baz"] | ||||||
``` | ||||||
|
||||||
In some cases, this could allow us to write programs that are more efficient than if we used a list. | ||||||
|
||||||
However, the size of an array is fixed. To add additonal items to an array, we must append them together, which would create a brand new, third array: | ||||||
|
||||||
```grain | ||||||
import Array from "array" | ||||||
|
||||||
let one = [> 1] | ||||||
let twoThree = [> 2, 3] | ||||||
let oneTwoThree = Array.append(one, twoThree) | ||||||
|
||||||
print(oneTwoThree) // [> 1, 2, 3] | ||||||
``` | ||||||
|
||||||
Since `oneTwoThree` is a brand new array, updating values in `one` or `twoThree` doesn't affect the values in `oneTwoThree`. | ||||||
|
||||||
For long arrays, even when adding just one element, this could be a fairly expensive operation. For programs that need to do this kind of operation, lists may be a better choice. We discuss this in more detail in the section below. | ||||||
|
||||||
To learn more about what's available in the Array standard library, check out the [array standard library documentation](https://grain-lang.org/docs/stdlib/array). | ||||||
|
||||||
## Lists vs. Arrays | ||||||
|
||||||
Lists and arrays are similar constructs, but each has its own pros and cons. It's up to you to choose which is right for your use case! | ||||||
|
||||||
Lists are excellent because they're | ||||||
|
||||||
- immutable | ||||||
- efficient at adding additional elements | ||||||
- efficient at removing elements | ||||||
- easy to work with | ||||||
- less succeptible to bugs | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In what way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No possible There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, expanding might be valuable because "take our word for it" seems like a bad position for our "guide" 😛 |
||||||
|
||||||
Lists might not be the right choice because they're | ||||||
|
||||||
- unable to be modified in place | ||||||
- inefficient at accessing random elements | ||||||
- inefficient at determining the number of elements | ||||||
|
||||||
Arrays are excellent because they're | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the list would have to be reworded if these are both changed to "at" but I think it's best to say what they are "excellent at" |
||||||
|
||||||
- able to be modified after creation | ||||||
- efficient at accessing random elements | ||||||
- efficient at determining the number of elements | ||||||
|
||||||
Arrays might not be the right choice because they're | ||||||
|
||||||
- inefficient at adding additonal elements | ||||||
- inefficient at removing elements | ||||||
- more succeptible to bugs | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
As a rule of thumb, lists are the idiomatic choice in Grain! Lean towards using lists whenever possible and use arrays when it makes your code easier to understand. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You might want to state that Lists are more idiomatic because they are generally easier to work with and more feature rich supporting destructuring in pattern matches and the fact that they are less likely to throw runtime errors. you might also want to note that as grain is functional lists are the better choice because you they are immutable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This rule of thumb more accurately paints the picture of determining the most efficient data structure for the use case. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
title: Loops | ||
--- | ||
|
||
Loops allow you to repeat an action over and over (and over). | ||
|
||
## While Loops | ||
phated marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The most basic loop is the `while` loop. The code within the loop repeats until the condition is `false`. | ||
|
||
```grain | ||
let mut i = 0 | ||
|
||
while (i < 10) { | ||
print("looping!") | ||
i += 1 | ||
} | ||
``` | ||
|
||
Loops can skip to the next iteration using the `continue` keyword. For example, to print only the odd numbers from zero to ten: | ||
|
||
```grain | ||
let mut i = 0 | ||
|
||
while (i < 10) { | ||
if (i % 2 == 0) continue | ||
print(i) | ||
i += 1 | ||
} | ||
``` | ||
|
||
Use the `break` keyword to exit from a loop entirely: | ||
|
||
```grain | ||
let mut i = 0 | ||
|
||
while (true) { | ||
if (i < 10) { | ||
print("forever?") | ||
i += 1 | ||
} else { | ||
break | ||
} | ||
} | ||
``` | ||
|
||
## For Loops | ||
|
||
`for` loops are just like `while` loops, just with more structure. `for` loops accept an optional initializer statement which runs before the loop, an optional condition statement which runs before each iteration, and an optional increment statement which runs after each iteration. | ||
|
||
`for` loops are commonly used to iterate arrays: | ||
|
||
```grain | ||
import Array from "array" | ||
|
||
let strings = [> "foo", "bar", "baz"] | ||
|
||
for (let mut i = 0; i < Array.length(strings); i += 1) { | ||
print(strings[i]) | ||
} | ||
``` | ||
|
||
As all of the loop parameters are optional, they can all be omitted (though the semicolons are still required). Omitting the condition results in an infinite loop: | ||
|
||
```grain | ||
for (;;) { | ||
print("forever!") | ||
} | ||
``` | ||
phated marked this conversation as resolved.
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
there
was a better transition here because, it goes on to list the properties rather than use cases.at
indicates listing specific examples. It might make sense to say something likeThe downfall of that sentence structure is you lose the nice list though a better option over a list might be having the two paragraphs with their differences and then using a table to compare the features.