-
Notifications
You must be signed in to change notification settings - Fork 36
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
Want to integrate this source generator into your project as a 'experimental feature'? #66
Comments
It looks incredibly cool. Something I hadn't even thought about. So it takes a standard This is very interesting! :) |
This is super cool. A few questions:
|
@genaray As for your questions:
Precisely, it just finds the calls to World.Query, extract the AST of the lambda you are passing to it to iterate the components and then "paste" it in the interceptor, rewritting what is needed to make it work (like adding the for loop and replacing Optimizer.OutOfScope calls to the raw version outside the loop).
It does not directly "replace" the World.Query, interceptors are more like "compiler will redirect calls from World.Query into your interceptor at compile time", so it's more "replacing the call" than the method itself (this allows a per-call optimization instead of something more general).
I don't think I understood your question, are you asking wheter the interceptors can only be static methods, or if you can intercept anything? I want to work on it more to improve the codegen and make it more reliable this weekend as well.
Yeah, this is like one of the most annoying problems about it currently... interceptors can only accept 'this' parameters and the parameters the function you are intercepting declares, so you cannot use lambda captures inside the code-generated interceptor (unless I find any way to do so, which is unlikely because C# does not allow you to modify the source code by source generators). I think this can be alleviated if you make the method itself accepting a generic parameter arbitrarily to pass around to the lambda, or maybe by using an extension method (I just thought about it now; it might work)?
Hmmm, I don't think I get it, can you explain to me what it is? OutOfScope currently just replaces the lambda inside with a variable outside of the loop scope, like this:
Oh, certainly! I'm using this solution because it:
|
So all in all this looks very very promising and I would be happy to either integrate it into Arch.System.SourceGenerator or offer it as a new package. Depending on what makes sense :) Maybe you could even use similar techniques in some places to get even more out of Arch. We'll have to see about that. Would you be willing to provide the project and add it to Arch.Extended? :) |
Amazing! Yeah, I'm willing to provide it. I've published it to a repository, which I'll link here below for you. This way you can decide which approach you find the best: Integrating with the Arch.System.SourceGenerator or creating it as a new package I was also working on some changes like this: I also made a csproj analyzer to check for the interceptor configuration on the csproj, but it was kinda frustrating because apparently you cannot do code fixes or appropriate infos/warnings/errors in a .csproj, so I later removed it.
Do you have any suggestions about these other places? I'm interested in exploring the possibilities you may have in mind. |
I had a quick look at your code and it looks great so far, good work :) I think it would make the most sense as a new package in Arch.Extended. The only thing I would suggest for such an integration would be to split the code a bit more to make it more readable. You can use Arch.System.SourceGenerator as a guide. A model is created there which is processed further to generate code from it. Makes it a bit more readable (in my opinion). Or what do you think? :) |
Hi! Thanks for reviewing the code! And also apologies for the delayed response, my job made me particularly busy this last week. I agree with your suggestion on enhancing the code. While I also value the readability of having what I need in one sequential place, I think this code as it is will benefit by being more split and organizing some things. I'm commited to make these changes and align the style of the code to be more like Arch.System.SourceGenerator. I'll start making these adjustments this weekend when I can dedicate focused time on it. |
No problem, we're all busy sometimes! :) That sounds great so far, I can hardly wait. Let me know as soon as you make progress ^^ |
Had time yet? :) |
Hi! Yeah, last week not much hahaha, but I worked a bit on it, and today I finished. I used your project as a reference point and at the same time tried to keep it in line with how it was structured originally. I think it is more readable and easy to follow now! Please, take a look when you have some time and tell me what you think. |
I apologize for the late reply, somehow I didn't get a notification. I'll take a look tomorrow and give you some feedback, I'm curious! :) |
Hi, I'm back! No worries about the delay. But anyway, let me know when you have the feedback of the code, I'm also curious! |
I had a look at the code now, all in all it looks good! I would like to integrate it directly, but unfortunately I have a lot on my plate at the moment. But as soon as I have some free time again, I'll take advantage of it. Your other plans also sound very interesting ^^ |
No problem, thank you very much for the feedback! |
A week ago, I developed this source generator in some hours for a experiment I thought was interesting, it uses the new .NET feature called 'Interceptors' to intercept the 'prototype-style queries' and turn them into the more 'boilerplate and fast' version as a method.
As an example, it will take this:
(this ISystem is a part of a game I'm making with arch, it is a custom thing for my needs; the 'Optimize' attribute can be applied on any kind of function with as many queries as you would like)
And will turn into this:
(it's not being generated formatted currently, but it works and kinda the generated code is the same for all instances, so it should not produce any bugs)
So basically, what this does is take the closure AST and turn it into an actual boilerplate-like query, using the closure body as a simple C# block in the generated output. It also replaces any Optimzer.OutOfScope call with an actual out of scope variable, inlining the closure expression as the variable initializer (and the actual variable declaration as the, well, variable declaration).
I made some benchmarks, and it appear to have similar (or better) performance than the source generated queries, and in relation to the closure prototype non-optimized version they have marginal gains, and substantial gains when accessing objects out of the closure (I suppose because of the inlining).
These where some of my tests for it:
The 'Query' version is the normal prototype one, the optimized is the prototype one with code generation and my interceptors, the manually optimized one is the version I wrote manually in place, the simpler is not using unsafe and instead querying manually from the entity each iteration, and the last is your version. I think the benchmarks can be enhanced, but it sounds promising from my tests.
I still want to do some improvements here and there, and cover some edge cases (as well as adding compiler errors for non static queries and automatically infering the static method calls to the source type without needing to specify it manually, and add some testing as well), but I thought this would interest you and I'm curious if you would want to export this project if I publish it or is willing to put it inside the extended repository.
The text was updated successfully, but these errors were encountered: