Skip to content
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

Borrowing for var T and lent T to improve Nim's memory safety #7373

Closed
Araq opened this issue Mar 19, 2018 · 4 comments
Closed

Borrowing for var T and lent T to improve Nim's memory safety #7373

Araq opened this issue Mar 19, 2018 · 4 comments
Labels

Comments

@Araq
Copy link
Member

Araq commented Mar 19, 2018

This proposal finally solves issue #124 by a simple borrow checking rule: A return type of var T is assumed and enforced to be a view into the location reachable by the first parameter of the proc.

Every known usage of var T in the standard library is derived from the first parameter. Other code like

var global: int
proc foo(): var int = global

will fail to compile. Furthermore the analysis needs to forbit mutating operations on the collection for as long as the var T views are "borrowed". Since let x = returnsVarT(collection) conceptually turns the pointer view into a copy, this borrow check should be rather easy to enforce. I hope.

Let us see how this outlined borrowing rule solves #124:

proc forward[T](x: var T): var T = result = x # ok, derives from the first parameter.
proc p(param: var int): var int =
  var x: int
  result = forward(x) # Error: location is derived from ``x`` which is not p's first parameter.

Future directions

Later versions can be more precise with a syntax like

proc foo(container: var X): var T from container
@Araq Araq added the RFC label Mar 19, 2018
@mratsim
Copy link
Collaborator

mratsim commented Mar 19, 2018

First param only sounds a bit unfinished.

Also I feel like I'm also talking a lot about FP but:

iterator mzip(container1: var seq[C1], container2: var seq[C2]): (var C1, var C2) =
  ...

also var T scope container is too scary.

@zah
Copy link
Member

zah commented Mar 21, 2018

I'm not sure what from would mean in the presence of additional indirections:

type
  SeqHolder = object
    data: seq[int]

proc foo(x: SeqHolder): var int =
  return x.data[0]

My initial thoughts are that the sequence slots can be indeed treated as part of the SeqHolder location (even though they are stored elsewhere on the heap), but I'm not sure how to define this relationship for other user-defined container types. Also, perhaps we'll benefit from a more precise borrow checker that can notice that only the data field has an active "var view".

Otherwise, I don't see how limiting the borrow checker to a single param makes things easier. Looks like the job will be only slightly harder when more locations are involved.

@Araq
Copy link
Member Author

Araq commented Mar 21, 2018

Otherwise, I don't see how limiting the borrow checker to a single param makes things easier.

It's not about ease of implementation. It's about how to make the existing var T safe without introducing more syntax. Right now var T is too sloppy to make memory safe.

@Araq
Copy link
Member Author

Araq commented Mar 22, 2018

Since globals live forever, taking their address is always safe. So result = global can continue to be allowed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants