-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[superseded] ref syntax for lvalue expressions: byRef: myref=x[1].foo[2]
#11824
Conversation
These seem out of place in |
There is a way to implement this in the compiler while preserving memory-safety. It would be a larger reform that would also allow a more relaxed usage of the |
Just to ensure we're on the same page: "stack location" is the wrong idea for this, there must be some kind of borrowing going on. I propose to re-use the "location is derived from the first parameter" idea that we use for |
I'll try to clarify: Let's use the term "referenced object" for an object owning memory that can be pointed to by a var/lent/openarray pointer. When I say "stack location", I'm referring mostly to the lifetime aspects. To ensure safety, you need to know that the lifetime of the referenced object is strictly enclosing the lifetime of the pointer. This is ensured when the pointer is a part of a newly created stack variable, because the lexical scopes ensure that this stack variable will be destroyed before the referenced object is destroyed. The pointed memory itself can live on the heap (as it would be the case when you obtain an It the RFC, I'll explain how there is an isomorphism between the new rules and the current language features - every code written with the relaxed rules can already be written by extracting the continuation of a proc at a given line to a separate proc where the |
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.
better syntax: byRef: foo = expr vs alias(foo, expr)
I prefer the latter. My favourite would be:
alias:
foo = expr
I guess you've decided to use byRef
because you wanted to implement byPtr
too, but AFAIK that separation is unnecessary.
@dumjyl
done. PTAL, all comments addressed, except for @zah's comment (#11824 (comment)); my understanding is this would be a much more involved change, and that if it materializes it can be done in a backward compatible way to support more things inside |
e8b060f
to
b437242
Compare
byRef: myref=x[1].foo[2]
byRef: myref=x[1].foo[2]
@dom96 this is PR is still marked as "change requested", I believe I've addressed all comments so far; in general "changes requested" option is overkill compared to just "leave a comment" option, as it tends to stay there even after the comments were addressed |
IMO the only thing left is bikeshedding about the names and whether it shouldn't be a Nimble module first, before we add hardly proven "syntax sugar". I quite like it though and maybe the chances we got it wrong are slim? |
b437242
to
3c51aec
Compare
3c51aec
to
0896919
Compare
/cc @Araq ping
|
Time moved on since then and I don't like it much anymore. Firstly the name should not contain |
it's not just about escaping: the point is to use block byPtrfBlock:
type Foo = object
x: string
proc fun(a: Foo): auto =
doAssert not compiles (block: byRef: x=a.x) # good, byRef prevents you from modifying immutable variable `a`
byPtr: x=a.x # byPtr is more dangerous, allows you to modify immutable `a`
x[0]='X'
let foo = Foo(x: "asdf")
fun(foo)
doAssert foo.x == "Xsdf" also, |
Fair enough but then the |
the situation is exactly symmetrical with byRef (via addr) vs byPtr (via unsafeAddr); If you just use byPtr: x = foo.bar[2].baz
x+=12
fun(x)
echo x with let x = foo.bar[2].baz.unsafeAddr
x[]+=12
fun(x[])
echo x[] |
Yes, I know. |
PTAL; removed byPtr from this PR to unblock this (I hear your arguments and it's a sugar vs bloat tradeoff) |
Well now it needs a good name, |
051a689
to
0e66b9a
Compare
This comment has been minimized.
This comment has been minimized.
can whoever (anonymously) marked my PTAL comments as spam kindly let me know why they did so? a PTAL (please take another look) comment is commonly used to indicate that all reviewer comments were addressed (or need reviewer input) and that the PR is ready again for the reviewer to take a look. It also makes it visually clear when looking at a PR whether it's pending on reviewer or PR author. This practice is common both in tech companies as well as in open source, eg: |
Be assured it wasn't anybody from the core team. :-) |
ping @Araq |
The feature is fine now except I think it's ugly. Not your fault, but I want something like |
but that's impossible, the colon is needed; did you see my answer here #11824 (comment) ?
macro byAddr*(def: untyped): untyped {.parse_as_var_definition.} = ... But I don't see how something like that could be implemented robustly, as the parser would have to have access to semantic analysis when resolving something like And I don't think we should introduce a new builtin keyword for that feature, which is just a library thing, because other similar constructs may be needed (eg I think |
Well we can add a keyword to the language. Or maybe we can/should do |
that's more ugly, longer to type, and is confusing (given that you can write so I opted for a new keyword:
=> see #13342 will close this PR if other PR is greenlighted |
byRef: myref=x[1].foo[2]
byRef: myref=x[1].foo[2]
superseded by #13508 |
this PR introduces a ref syntax for lvalue expressions, similar to what you can do in C++ with
auto& a = someExpr()
compared to #11686 and prior attempts, there are 4 advantages:
byRef: foo = expr
vsalias(foo, expr)
See example2 vs example 3 below for the comparison
By design, it only works with lvalues and will give a CT error on non-lvalues (for which ref makes no sense).
It is a pure library solution.
example 1: simple example
example 2 illustrating side effect safety, type safety
example 3: comparison vs #11686
note
alias: myecho=echo
to alias any symbol #11822 which defines analias
syntax that works with symbols instead of lvalues, it's a different conceptbyPtr
is analogously defined in this PR for cases whereunsafeAddr
is needed instead ofaddr
, eg for unsafe access to non-var params; it is useful in some situations[EDIT]
addr
orunsafeAddr
since the address doesn't escape the scope where it's definedbyRef: foo*=bar