-
Notifications
You must be signed in to change notification settings - Fork 8
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
Builder Pattern applied to the Builder struct, errors instead of panics #8
base: master
Are you sure you want to change the base?
Conversation
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.
First of all thanks for the pr!
Overall changes look good, but I have problem with the errors that result from wrong usage of the builder API itself and I would like to hear your rationale on them.
Atleast the name of the configuration struct has to be renamed before merge. Or if you can convince me that it's good idea, then all other places I have used same reasoning needs to be changed to keep the API consitent :P.
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct PoissonConfiguration<F, V> |
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.
Having configuration object way better than what was before. I felt weird having all kinds of methods taking builder as parameter.
I would change the name to just Configuration
as I have done with Generator
, Algorithm
and others.
The idea is that from outside perspective we have poisson::Configuration
instead poisson::PoissonConfiguration
.
If the user has conflict with their own type/trait or with another librarys they can always do:
use poisson::Configuration as PoissonConfiguration;
.
pub struct Builder<F, V> | ||
/// This is the error type for the `Builder::build` function. | ||
#[derive(Debug, PartialEq, Eq, Copy, Clone)] | ||
pub enum ConfigurationError { |
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.
Hmm... When I was first writing the code I didn't go with custom error as all the errors were caused by missuse of the API and thus programming errors which means that there isn't anything meaningful to do if code triggers them.
Maybe if one calculates radius via other code before setting it via builder then it could have use?
So maybe custom error is better anyways.
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 also don't really like having *Unspecified errors as they are coding errors and there is nothing to do about them run time.
And *MultiplyDefined errors seem odd too as setting value twice isn't nessacary error and can just restrict the APIs usage.
If the errors were encode type system ala session types I would feel better about them. But that would feel bit too heavy for this.
Have to think about this.
Thanks for the reply. The The I like session types. I don't like that implementing them involves so much manual labor. Tracking the About the naming of the configuration struct you are absolutely right! I'll change it, probably tomorrow. |
What is your opinion on the |
I get what you mean by not wanting to crash ever, but if your code comes up into case where no radius is specified what can you do to recover from it? I do agree now that panicing was bad choice anyways: It doesn't show up in the type signature. I should really play around with the session type idea as that would fix the problem. Maybe macros could be used to reduce the boiler plate involved? Would have to use generics for the builder because macros cannot create indents. Maybe this error type solution should merged meanwhile until viability of session types is confirmed... I think that using |
Here is the start of implementing the session type based builder pattern with macro. Setters aren't implemented yet as they need more complex token tree munching. Also to implement error checking there needs to be a way to provide custom build method. |
and here is version that has working setters. It doesn't yet work with generic or optional variables and doesn't include custom build method. |
Wow, that's some impressive macro magic!
For example there could be a popup "error generating tree positions" and the game could run without trees. |
and now it has optional variables. |
Thanks! Ah.. Interesting. I didn't think anything like that. That is basically same idea that led to how html/php/javascript or any web technology handles errors. Which is one reason I don't really like them and are attracted by static typing (Keeping broken program running is asking for trouble imho). But I do understand that you don't really want to crash your server. But in other hand you propably are catching panics coming from job threads in them anyways. I can now see where you are coming from and having those errors would be good. Or just using session type builder :P |
I think I have sunken into rabbit hole... Now it has support for single constraints on generic values. |
It's a huge difference whether the language tries hard not to crash or you try not to crash. If at some point an array is filled with NaNs instead of trees, because the language thought it was smart to fail as late as possible, you're f...rankly not in a very nice situation. I do not defend the concept fail-late or its employment by any language such as JavaScript, PHP, Ruby, Python etc.
Nice. See what you can find down there and maybe put it in a crate and bring it back up, so everyone can profit from your journey. I just recently thought about the "session types" concept: "Why is there no crate for this?" |
Now it has full generic support. pub mod Builder {
use super::*;
pub struct O;
pub struct I;
pub struct Builder<T1, T2, ..., Tm, C1, C2, ..., Cn>
where //bound that affects Cs
{...}
pub fn new<T1, T2, ..., Tm, C1, C2, ..., Cn>() -> Builder<O, O, ..., O, C1, C2, ..., Cn>
where //bound that affects Cs
{...}
// Setters. These require that there is O in the place that is set
// and return Builder where that place is replaced with I
impl Builder<I, I, I, ...> {
pub fn build(self) -> Config {...}
}
pub struct Config<C1, C2, ..., Cn>
where //bound that affects Cs
{...}
impl Config<C1, C2, ..., Cn>
where //bound that affects Cs
{
// Getters
}
}
pub use Builder::new as Builder;
pub use Builder::Config; which is kinda funky:
|
Ah... I see your point clearly now. Lets remove all possible panics that user can cause and replace them with session types and error types then. |
As custom derives become stable with macros 1.1, I went and implemented builder generation library with them. It should work on most use cases (even more than then the macro solution), but it's pretty ugly code. |
Using |
The issue should be resolved and I added some documentation. |
I updated the library to use Should I update the pr or are you willing/wanting to do it yourself? Also the issue that you reported for |
Sorry, I didn't have time to look into it. |
implements #7