-
-
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
Make await a template #12085
Make await a template #12085
Conversation
it also helps #11911 (comment) and adding stuff like waitFor check |
What does that do? Enable |
Yes, now i can use it in templates : but it also makes await a template which is a cleaner implementation compared to checking for idents (and one can easily implement other stuff like |
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.
This is cool, but the async
macro still has code which processes await
. You should remove that code to make sure your template is actually being used.
ed04b24
to
6bd3a38
Compare
Any updates on this? |
sorry, i left some comments but not sure if easily visible: it doesnt work for some reason with T : something like "expr has no type" errors, it really doesnt seem obvious to me why this is for the review task to use |
That's fine, but there are other comments that need resolving. |
ok, i'll try to push a fix for those |
c89dc26
to
873cd78
Compare
ok, the only remaining issue seems to be that |
873cd78
to
ad74a13
Compare
EDIT: ok code fixed (dont merge yet: wanted to remove some code) otherwise Araq said https://irclogs.nim-lang.org/16-04-2020.html#13:51:11 so i'll leave the test as that (even though i think it might be leaking as it constantly deallocates less) |
937ef93
to
58ebdb9
Compare
ok, now it should be ready, also used |
sorry, the changes comment about code processing await seems to be for outdated older changes: please review the fresh ones
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.
I like these changes a lot, but there are a couple of things that I think still need to be resolved. Sorry about the back and forth.
This time I was very thorough so this should be the last of it.
lib/pure/asyncmacro.nim
Outdated
template await*(f: untyped): untyped = | ||
when declared(retFuture): | ||
static: | ||
error "await expects Future[T], got " & $typeof(f) | ||
elif not declared(inMultisync): | ||
static: | ||
error "await only available within {.async.}" | ||
else: | ||
f |
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.
From what I can tell this is only here to allow multisync to work. It took me a while to figure this out, can you add a comment to explain this?
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.
Actually, now that I look at the code above, I would just remove this and keep the stripAwait
logic in splitProc
. Adding this inMultisync
variable into the generated code is more hacky. That way you can also reuse the compiler's type mismatch error messages.
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.
i really think this is also elegant: after all you change how this works quickly with high level code flow without any ast surgery. inMultisync should be somehow optimizeable, its needed only on compile time
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.
A loop which modifies the AST may be more code, but it's also far more deterministic and easier to debug should something go wrong. Hygiene is important and generating variables so that you can then check for their existence is flaky. The current multisync macro does what it needs to do, and then gets out of your way.
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.
but .. wouldn't this break templates again? after all you wouldn't be able to generate await in multisync, i think
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.
oh, you mean if a template using await
is used in a multisync proc? I think you're right. But in that case, can we resolve that in a separate PR? I just like to keep this clean.
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.
ok, but we really shouldn't get into a situation where just one of the cases is fixed.. they are symmetric
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.
ok, no we dont need those variables anyway, so i think this can be still one PR
lib/pure/asyncmacro.nim
Outdated
@@ -257,7 +178,7 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = | |||
outerProcBody.add(prc.body[0]) | |||
|
|||
# -> var retFuture = newFuture[T]() | |||
var retFutureSym = genSym(nskVar, "retFuture") | |||
var retFutureSym = ident"retFuture" |
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.
Why was this changed? Without genSym
here if someone declares a retFuture
of their own then there will be a clash...
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.
in order for await to be able to check for this symbol in when IIRC
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.
Ahh. Yeah, I'm not the biggest fan of this. If someone accidentally defines a retFuture
in their proc then it'll be considered async (that behaviour will be very confusing).
I wonder if we can come up with a better way to detect async procs, can you check if compiles(yield f)
works? :)
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.
interesting idea, but this would work in another iterator as well ! which we still don't want.
maybe i can generate a symbol which can't be written by users similar to :env
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.
but this would work in another iterator as well ! which we still don't want.
IMO it's not the worst thing if it does work, it'll only work if that iterator's return type is a future and if a future is awaited, so likelihood is that it will make sense anyway.
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.
we can do something else : we can just leave out template await
and and generate just one in of async
: Future[T] working and one in multisync sync: which works for every type: all other cases just fail like normal overloads!
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.
this way we can really just use the default nim mechanisms for most of the errors as well (await just isn't defined somewhere, or it just doesnt accepts int somewhere)
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.
and if we really want to we can still leave a global overload which errors with a more detailed message as a fallback
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.
this works!
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.
i'll push a new commit when i test it a bit
@@ -110,13 +110,15 @@ Async traceback: | |||
## Executes pending callbacks | |||
asyncmacro\.nim\(\d+?\)\s+?fooNimAsyncContinue | |||
## Resumes an async procedure | |||
tasync_traceback\.nim\(\d+?\)\s+?fooIter | |||
asyncmacro\.nim\(\d+?\)\s+?fooIter |
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.
This actually reduces the amount of signal we get from the async tracebacks. I cannot recall whether this particular line provided useful information, but if it does then that could be a blocker for these changes. Can you run this test and show us what the tracebacks are before and after your changes?
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.
IIRC the change is similar to what is seen in the diff, basically we need to add the linedir of tasync_traceback
to the result of template somehow maybe?
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.
I want to see what line the traceback points to now.
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.
asyncmacro.nim(261)
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.
which seems to be (cast[type(f)](internalTmpFuture)).read()
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.
That should be okay, I'm assuming that tasync_traceback
in the old traceback doesn't point to anything interesting though.
58ebdb9
to
4ec022e
Compare
ok, so now we generate this can be hinted in an error message tho |
sorry! it seems we can just skip the global overload fallback with a custom error and then template without annotation |
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.
I love it, but please check with @Araq that this won't slow down compilation. Generating so many copies of the same template seems like it could go badly :)
@@ -332,8 +253,24 @@ proc asyncSingleProc(prc: NimNode): NimNode {.compileTime.} = | |||
if returnType.kind == nnkEmpty: | |||
# Add Future[void] | |||
result.params[0] = parseExpr("owned(Future[void])") | |||
|
|||
# based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 |
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.
I would remove this comment, at this point this really doesn't have many parallels. I doubt it'll be useful for those exploring this code.
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.
well, I still got the "define await as a template" overall approach from there, but I am not sure what's the best way to document that stuff
# overload for await as a fallback handler, based on the yglukhov's patch to chronos: https://github.com/status-im/nim-chronos/pull/47 | ||
# template await*(f: typed): untyped = | ||
# static: | ||
# error "await only available within {.async.}" |
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.
You still need this, no?
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.
oh, you removed this because you didn't want dirty
. Is dirty
really that bad? :)
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.
no, but it can be a bit surprising: we need to somehow hint here in the error "if you use a template, you might want to use {.dirty.}
" because otherwise many users would be just confused by why just a template/macro can't work
on the other hand just a type mismatch/undefined error is very natural, await
is not found and that's it
result[0][3][i][1] = splitParamType(result[0][3][i][1], async=false) | ||
var multisyncAwait = quote: | ||
template await(value: typed): untyped = | ||
value | ||
|
||
result[0][^1] = nnkStmtList.newTree(multisyncAwait, result[0][^1]) |
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.
I love it :D
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.
credit to @zah's idea #11911 (comment) i think i finally remembered this is also possible
Ok, I was wondering about that as well, maybe the compiler should be able to somehow cache such cases (applicable for other template/macro applications) |
I don't see the copies here, what do you mean? |
Araq, it's about inserting two |
I cannot imagine these 2 little templates are noticable, merging. |
The `check eventually` template is incompatible with Nim 1.2. It uses `await` in a template, which is not possible until after 1.2. nim-lang/Nim#12085 (comment)
The `check eventually` template is incompatible with Nim 1.2. It uses `await` in a template, which is not possible until after 1.2. nim-lang/Nim#12085 (comment)
Adapted status-im/nim-chronos#47 for asyncdispatch with support for multisync : credit for the original impl to @yglukhov !