Understanding Subscripts #739
-
Hi, I'm having a hard time understanding subscripts and their use. Currently what I understand I that val functions can't/don't return references and only return values, subscripts are there to fill the use case of functions that return references. I assume that subscripts do it in a way that is safe and does not require us to use lifetime annotations like rust. But that's just me and I would be grateful if someone can point if I understand and provide more insight into subscripts. |
Beta Was this translation helpful? Give feedback.
Replies: 0 comments 6 replies
-
Hi @AbhinavK00! Your understanding is relatively accurate. In general, I think it's best to just forget about references when reasoning about Val. The reason is that, although projections (i.e., the result of a subscript) fill a similar role, they do not represent a distinct kind of values, with a distinct type. For example, in C++, a reference to So if it's technically correct to say that "Val functions can't return references", it's important to note that it simply derives from the fact that references don't exist in Val. Unlike functions, subscripts don't return values, they project them until they are no longer used by the caller. That's an important difference. Projecting doesn't make values escape (we'll come back to that); all operations can happen in-place and nothing has to "move". For example, when we write fun f(_ i: Int) { print(i) }
public fun main() {
let x = Array([0, 1, 2, 3])
let y = x[2]
f(x[2])
f(0)
} Notice that Subscripts are not the only way to project a value. Passing arguments to References à la C++/Rust require lifetime annotations because the type That's where escape comes back. Val's type system keeps track of the values that are allowed to escape and those that aren't, based on their ability to move and their outstanding uses at a given program point. For example, consider the following program: fun forty_two() -> Int {
let x = 42;
let y = x
print(y)
return x
} If the caller of Escaping a value requires it to be not bound by any other binding still in use and that its type be fun consume(_ x: sink Int) {}
public fun main() {
let x = Array([0, 1, 2, 3])
let y = x[2]
consume(y) // error: `y` cannot escape while `x` is let-bound
print(x)
} The call to |
Beta Was this translation helpful? Give feedback.
Hi @AbhinavK00!
Your understanding is relatively accurate.
In general, I think it's best to just forget about references when reasoning about Val. The reason is that, although projections (i.e., the result of a subscript) fill a similar role, they do not represent a distinct kind of values, with a distinct type. For example, in C++, a reference to
int
has typeint&
orint const&
. In Rust, a reference toi64
has type&i64
or&mut i64
. In Val, a projection ofInt
has typeInt
.So if it's technically correct to say that "Val functions can't return references", it's important to note that it simply derives from the fact that references don't exist in Val.
Unlike functions, subscripts don't re…