BorrowScript icon indicating copy to clipboard operation
BorrowScript copied to clipboard

What about lifetimes?

Open hazer-hazer opened this issue 2 years ago • 4 comments

Rust has a feature "lifetimes" for reference validation. Of course, it is possible to reduce cases when explicit annotations are required and don't have them at all in the language. Anyway, are there any plans for lifetime annotations? If not, how would cases such as "reference field in structure/class" be checked?

UPD: I'm talking about cases like ...<'a> or &'a ....

hazer-hazer avatar Oct 01 '21 15:10 hazer-hazer

I think copying Rust's & syntax makes sense, unless we want to have a more explicit keyword.

On Fri, Oct 1, 2021, 11:27 AM Hazer Hazer @.***> wrote:

Rust has a feature "lifetimes" for reference validation. Of course, it is possible to reduce cases when explicit annotations are required and don't have them at all in the language. Anyway, are there any plans for lifetime annotations? If not, how would cases such as "reference field in structure/class" be checked?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/alshdavid/BorrowScript/issues/17, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGDQCMQOXZYYSSJ3M3CARGLUEXHMXANCNFSM5FE6ENEQ .

SuperSonicHub1 avatar Oct 01 '21 19:10 SuperSonicHub1

Good question. It's actually a bit tricky. To start with, all builtin types are references.

let a: number = 0
a.increment() // mutate the reference to a

Let's write a function that compares two numbers and returns the largest

function main() {
  let a = 5
  let b = 10
  let c = largest(a, b)

  console.log(c)
}

function largest(read x: number, read y: number): number {
  if (x > y) {
    return x
  } else {
    return y
  }
}

Somewhat similarly to Rust:

function largest<'a>(read 'a x: number, read 'a y: number): 'a number {}

// or we can use the 'lifeof' keyword
function largest<lifeof A>(read A x: number, read A y: number): A number {} 

I think this makes sense. number (like all builtin types) is a reference to an object instance and not a primitive value like i32.

What we are saying above is:

"Accept read-only references to variables x and y of type number. Return a reference to a number that has the shortest life of the parameters with the A life"

I think works if there are no non-reference value types. I don't like that the generic lifetime param is used differently to other type params.

This would look like:

function main() {
  let a = 5
  let b = 10
  let c = largest(read a, read b)

  console.log(c)
}

function largest<lifeof A>(read A x: number, read A y: number): A number {
  if (x > y) {
    return x
  } else {
    return y
  }
}

Rust looks like:

fn largest<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
    if x > y {
        x
    } else {
        y
    }
}

fn main() {
  let a = &5;
  let b = &10;
  let c = largest(a, b);

  print!("{}", c);
}

alshdavid avatar Oct 02 '21 01:10 alshdavid

Though the return type irks me.

function largest<lifeof A>(read A x: number, read A y: number): A number {}

Specifically

): A number {}

We could have so that a lifeof parameter (A in this case) itself is a type that has a type parameter.

function largest<lifeof A>(read A x: number, read A y: number): A<number> {}

alshdavid avatar Oct 02 '21 08:10 alshdavid

Hmm... Now it sounds more and more like "Rust with TypeScript-like syntax", which is not really bad, but I'm not sure if it will work. Rustish safety system is fascinating and the idea of static garbage collection is mind-grabbing, however, some features cannot fully live without GC in runtime, especially JavaScript features. I have so many questions about how this idea is possible to be implemented, but it would be better just to wait until you and contributors will make something workable.

hazer-hazer avatar Oct 03 '21 02:10 hazer-hazer