-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
nix-errors-enhancement - error format demo #3466
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
Conversation
Looks great! A few quick style comments (haven't looked at the code in detail):
Is the |
Thanks for the feedback! I'll fix the style stuff. Pos: true! ColumnRange and nixFile are duplicating functionality from Pos. That's part of the integration problem I hadn't addressed yet. I don't think having both is the way to go, but Pos depends on Symbol, so pulling Pos out into libutil woudn't work. I could perhaps make a builder function in libexpr that would take Pos as an argument - assuming we keep the builders. More on that below. At any rate, ColumnRange isn't meant to replace Pos. format/fmt; ok - didn't know we were phasing out boost::format. I made the Hintfmt wrapper to ensure that all templated values in hints are automatically colored yellow, for consistency. I think it should be possible to have the automatic yellow feature and the variadic argument interface too. Sound ok? Re the builder interface. I get it with the templates - reading error.hh is a little hard on the eyes compared to a plain class. My justification for using the builder pattern over designated initializers is that the initializers are optional. For instance with the ErrLine class this works:
That's great, and it looks good. But this also works - no helpful designations:
And you can also leave things out, like so:
With the builder interface, you are guaranteed to have the same builder functions 'naming' each argument. Also with the builders, the sequence of functions is always the same. For adding hints, I was thinking the hint()/nohint() builder would be handy. Initially all errors could be created without hints, as they are now. They'd call function nohint() on create. As hints are added, it would be easy to find the errors still lacking hints by grepping for 'nohint()'. With designated initializers, you're looking for a lack of This could be taken a (draconian?) step further by removing the nohint() builder function, and then all errors without hints would be type errors. With the language errors, on the other hand, virtually all of them are already hints - templated text. We might start with hints for those, and add descriptions afterwards, in a similar fashion. So that's the case for the builder interface. Its easy to read at the call site at least! I like the ability to micromanage the syntax of error creation. But if its too much we can just go for a consistent calling convention, and keep error.hh simple. |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/marketing-team-can-we-present-nix-nixos-better/6249/38 |
If you post updates to a blog or the crowdfunding page of before/after of these I bet it would increase excitement and funding. Great work! |
Progress is made! I think I've addressed most of the concerns above. Highlights follow: Pos: It seems like a good thing to have all the ErrorInfo code in error.cc and error.hh. To that end, I've opted to use a template function to pull information out of Pos and store it in error info - its just file, line, and column at this point. The template function means there's no dependency on Pos, so all the error code stays in libutil. An alternative to this would be to make a subclass of ErrorInfo that lives in libexpr, or to just have a separate error class for libexpr. fmt, hintfmt I think having automatic yellow for templated values is a good idea, so I made a hintfmt function that does that, with the variadic syntax of fmt. It uses the formatHelper from fmt underneath. Unlike fmt, hintfmt returns a class, not a string. That way the constructor methods can require hintfmt usage. If you really want monochrome templated values you can get them with ANSI_NORMAL. Construction style: At this point, I have 3 variations.
https://github.com/bburdette/nix/blob/error-format/src/error-demo/error-demo.cc An example:
https://github.com/bburdette/nix/blob/initializer-style/src/error-demo/error-demo.cc I think this style looks pretty good. You can't put the parameters in out of order, it turns out, but you can omit them, or use a more conventional init style without designations. On this branch I restructured the ErrorInfo class a bit to allow using Pos to init an 'errPos' class.
https://github.com/bburdette/nix/blob/constructor-style/src/error-demo/error-demo.cc We lose the parameter naming with this approach, but parameters are non-optional, similar to the template builder approach.
error-demo location? Currently I have the demo program in src/error-demo/error-demo.cc. I moved it out of test/ since its not really a test, but then I'm not sure where else it should go. For now I just put it with the rest of the C++ programs. We can leave it there, move it back to test, or remove it completely. The next phase of this error project will be to make a PR that applies the format to existing errors and integrates with logging and so forth. That will make this demo program perhaps unnecessary. |
@edolstra as @bburdette is going to start using this all around the code base, would really appreciate a review to finalize the api. |
I think I would prefer the designated initializer style, mainly because it requires much less boilerplate code. Templates should be avoided IMHO. For example, the function
|
Ok thanks for the review. I've merged in the designated initializer style. The error class itself is quite simple, which is appealing:
The nixCode part has an ErrPos field, which you init with assignment like so:
ErrPos implements its constructor and operator= as templates though. I think the inheritance/virtual function approach may end up with more boilerplate than this, but I'll give it some thought and see what I can come up with. |
Ok I used inheritance to pull the info from Pos. I have that in a branch right now:
And then in nixexpr.hh, Pos implements the getters:
For reference, the template way was like this:
Either of these options is fine by me. Another way to go would be to subclass ErrorInfo and implement its interface in nixexpr.hh. That would look something like this:
Do any of these options appeal? I haven't prototyped the subclass one yet. Another way to go would be to bail on having one unified error class, and do error processing for the language stuff separately. |
@edolstra ready for re-review. |
This pull request has been mentioned on NixOS Discourse. There might be relevant details there: https://discourse.nixos.org/t/how-to-extract-signal-from-almost-useless-error-message/11733/13 |
This is the first C++ code from the nix-errors-enhancement project. Phase 1 of the project is to make an api for creating error objects, and to demo what they'll look like printed to a terminal. Check out the proposal document for more.
What's not included here is integration with the existing logging.hh, or with the exceptions in libexpr. That's for phase 2. This PR is mainly to check that we're on the right track API-wise, before proceeding to the next phase, which is to move the existing error messages over to the new format.
A good place to start in reading the code is the demo program, located at
tests/errors/main.ccsrc/error-demo/error-demo.cc. The demo is hooked in to the nix makefile, so it gets built along with everything else.Output looks like this: