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

new syntax for lvalue references: var b {.byaddr.} = expr #13508

Merged
merged 8 commits into from
Mar 23, 2020

Conversation

timotheecour
Copy link
Member

@timotheecour timotheecour commented Feb 26, 2020

TLDR

  • introduces a new syntax for lvalue references: var b {.byaddr.} = expr, eg:
var b {.byaddr.} = foo[0].funWithSideEffect(2).bar.myStr
# simply use b, it'll be via reference semantically
b.add "foo"
  • exact analog of C++ references auto& b = expr;
  • much better approach than existing alternatives:
## existing alternative 1: template
template a: untyped = expr
  # * will evaluate expr each time it's used (even if costly, or has side effects)
  # * won't detect invalid `expr` if `a` is unused
  # * doesn't give redefinition errors

## existing alternative 2: let
let a = expr # not a reference, does a copy

## existing alternative 3: explicit `addr`
let a = expr.addr
a[]+=2 # less convenient: requires a deref on each use
fun(a) # less safe: the reference can escape

compared to #13342 and #11824

(some of these are comparisons to only #13342 or only #11824 or both)

# using #11824 approach:
import sugar
var x = @[1,2,3]
byAddr: x1=x[1]
x1+=10
byAddr: x1=x[2] # should give a redifinition error but doesn't, and hard to do (`when declared` is too naive)
  • allows specifying type optionally:
    var b {.byaddr.}: int = s[0]
  • doesn't introduce a new keyword, only a new pragma just for var for now; so it's easier to extend, eg var b {.byunsafeaddr.}: int = s[0] if needed
  • syntax is just a pragma extension of a regular let statement
  • addresses the essential technical criticism from [superseded] new syntax for lvalue references: byaddr x = expr #13342 (comment)

And personally I would have used let/var x {.view.} = someLocation. Adding a new pragma before a new keyword seems good and so does keeping the let vs var distinction.

I can change to view which is short and explicit, but I'd rather do the change just once, after this is greenlighted

example

    var s = @[10,11,12]
    var a {.byaddr.} = s[0]
    a+=100
    doAssert s == @[110,11,12]
    doAssert a is int
    var b {.byaddr.}: int = s[0]
    doAssert a.addr == b.addr

future PR's

  • for now the var section with byaddr must have a single element, support for more than 1 could be added in future (will be backward compatible of course)
# ok
var
  b {.byaddr.} = expr

# not implemented
var
  b1 = expr1
  b2 {.byaddr.} = expr2
  b3 {.byaddr.} = expr2
var x = (1, 2)
var (a,b) {.byaddr.} = x

note

this should replace at least some use cases for shallowCopy and {.shallow.}

@Araq
Copy link
Member

Araq commented Feb 26, 2020

Pretty good. However, either use an AST to AST transformation inside semexprs only without the helper public symbols in system.nim, or let's fix pragmas for variables so that is can be done entirely as a template/macro.

@kaushalmodi
Copy link
Contributor

@timotheecour Can you please also document this in the manual in the Pragmas section: https://nim-lang.github.io/Nim/manual#pragmas ? Thanks.

@krux02
Copy link
Contributor

krux02 commented Feb 26, 2020

Aren't references a feature that is left out in Nim for reasons?

@timotheecour
Copy link
Member Author

timotheecour commented Mar 5, 2020

@Araq PTAL

or let's fix pragmas for variables so that is can be done entirely as a template/macro.

done

compiler now lowers var a {.foo.}: MyType = expr to foo(a, MyType, expr) with user defined foo (with appropriate checks)

there are othe applications for this new compiler feature besides the current byaddr, eg:

# wraps a decl behind getter and setter accessors, eg for debugging
var {.onAccessCallback.} x: int 

@timotheecour
Copy link
Member Author

timotheecour commented Mar 22, 2020

@Araq friendly ping (I'll rebase to fix changelog.md conflict after you greenlight this as the changelog changes often)

@timotheecour timotheecour force-pushed the pr_byAddr_hiddenDeref branch from 1ec0f41 to 8336443 Compare March 22, 2020 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants