-
Notifications
You must be signed in to change notification settings - Fork 13
More language guide edits #10
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,11 +115,6 @@ public fun greet(_ name: String) { | |
|
||
The statement `import Greetings` at the top of `Hello.val` tells the compiler it should import the module `Greetings` when it compiles that source file. | ||
Implicitly, that makes `Greetings` a dependency of `Hello`. | ||
{% comment %} | ||
The point of this change is that some people “hear” words as they read them, and if you have two | ||
distinct names with the same sound, especially whose spelling differs only by capitalization, it | ||
gets confusing. | ||
{% endcomment %} | ||
|
||
Notice that `greet` had to be made public so it could be visible to other modules. | ||
As such, it can be called from `Hello.val`. | ||
|
@@ -242,9 +237,6 @@ public fun main() { | |
``` | ||
|
||
The type of an expression can be retrieved, without evaluating the expression, using `type(of:)`: | ||
{% comment %} | ||
I understand, precedent from Swift, but… what purpose does `of:` serve here?! | ||
{% endcomment %} | ||
|
||
```val | ||
public fun main() { | ||
|
@@ -414,7 +406,7 @@ public fun main() { | |
} | ||
``` | ||
|
||
*Note: indexing a buffer outside of is either caught as a compile-time error, or causes the program to terminate at runtime.* | ||
*Note: indexing a buffer outside of its bounds is either caught as a compile-time error, or causes the program to terminate at runtime.* | ||
|
||
The type of a buffer is written either `T[n]` or `Buffer<T, n>`, where `T` is a type and `n` the number of elements in the buffer. | ||
All elements of a buffer must be initialized at the same time as the buffer itself, either by the means of a buffer literal expression, as in the program above, or by calling a buffer *initializer*: | ||
|
@@ -467,6 +459,13 @@ type Matrix3 { | |
} | ||
``` | ||
|
||
{% comment %} | ||
I don't know if we discussed this, but making the memberwise init public has API resilience | ||
implications. In particular, it means you can't simply add/remove stored properties, even if they | ||
were non-public, without breaking client code. I'd like to design some facilities for helping a | ||
library author to ensure API stability eventually. | ||
{% endcomment %} | ||
|
||
The type declaration above defines a type `Matrix3` with a single property of type `Double[3][3]`. | ||
The second declaration exposes the default memberwise initializer of the type, allowing us to create matrices by calling `Matrix2.init(components:)`: | ||
|
||
|
@@ -490,7 +489,7 @@ public fun main() { | |
``` | ||
|
||
In the program above, `m.components` can be modified because `m` is a mutable binding **and** the property `components` is mutable, as it is declared with `var`. | ||
Would that property be declared with `let`, the components of the matrix would remain immutable once the matrix has finished initializing, notwistaning the mutability of the binding to which it is assigned. | ||
Had that property been declared with `let`, the components of the matrix would remain immutable once the matrix has finished initializing, even though `m` is mutable. | ||
|
||
Members that are not declared `public` cannot be accessed outside of the scope of a record type. | ||
As we uncover more advanced constructs, we will show how to exploit that feature to design clean and safe APIs. | ||
|
@@ -520,8 +519,8 @@ public fun main() { | |
### Unions | ||
|
||
Two or more types can form a union type, also known as a [sum type](https://en.wikipedia.org/wiki/Tagged_union). | ||
A sum type is a super type of all its elements. | ||
Among other things, it means that if a type `T` is the union of the types `U` and `V`, then a binding of type `T` can be assigned to a value of type `U` *or* a value of type `V`. | ||
A sum type is a supertype of all its elements. | ||
Among other things, that means that if a type `T` is the union of the types `U` and `V`, then a binding of type `T` can be assigned a value of type `U` *or* a value of type `V`. | ||
|
||
```val | ||
public fun main() { | ||
|
@@ -551,13 +550,17 @@ The type `Option<T>` is the union of any type `T` and `Nil`, which can be used t | |
## Functions and methods | ||
|
||
Functions are blocks of organized and reusable code that performs a single action, or group of related actions. | ||
As a program grows in complexity, they become mandatory. | ||
They are an essential tool for managing the complexity of a program as it grows. | ||
|
||
*Note: Though Val should not be considered a functional programming language, it does support this style of programming relatively well, as functions are first-class citizen.* | ||
*Note: Though Val should not be considered a functional programming language, functions are | ||
first-class citizens, and functional programming style is well-supported. In fact, Val's mutable | ||
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. Nice! |
||
value semantics can be freely mixed with pure-functional code without eroding that code's local | ||
reasoning properties* | ||
|
||
### Free functions | ||
|
||
Functions are declared with `fun`, followed by its name, its signature, and finally its body: | ||
A function declaration is introduced with the `fun` keyword, followed by the function's name, its | ||
signature, and finally its body: | ||
|
||
```val | ||
typealias Vector2 = (x: Double, y: Double) | ||
|
@@ -573,8 +576,11 @@ public fun main() { | |
``` | ||
|
||
The program above declares a function named `norm` that accepts a 2-dimensional vector (represented as a pair of `Double`) and returns its norm. | ||
The signature of a function fully specifies its API. | ||
Most importantly, it describes the function's parameters and their type as well as a return type. | ||
{% comment %} | ||
The API of a function arguably includes the its semantics and preconditions. | ||
{% endcomment %} | ||
|
||
A function's signature describes its parameter and a return types. | ||
|
||
*Note: The return type of a function that does not return any value may be omitted.* | ||
*In that case, the declaration is interpreted as though the return type was `Unit`.* | ||
|
@@ -597,7 +603,7 @@ fun scale(_ v: Vector2, by factor: Vector2) -> Vector2 { | |
``` | ||
|
||
Argument labels are also useful to distinguish between different variants of the same operation. | ||
Further, note that Val does not suppoer type-based overloading, meaning that the only way for two functions to share the same name is to have different argument labels. | ||
Further, note that Val does not support type-based overloading, meaning that the only way for two functions to share the same base name is to have different argument labels. | ||
|
||
```val | ||
typealias Vector2 = (x: Double, y: Double) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
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 thought about that.
The idea is that if you want to change the layout of the type later on, you'll have to write a custom initializer to keep your promise. That's what you have to do in Swift today anyway. The memberwise init feature is just a shortcut for a large class of situations where your type does not cross a resilience boundary but also doesn't want to expose all its parts publicly.
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.
Yes! But the problem in Swift today is that AFAIK there's nothing in place to discourage you from changing the layout of your type once you've made the promise. Actually in the case of API it's not necessarily about layout, just about which members are stored.