Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

[WIP] Add boxed-error feature. #69

Closed
wants to merge 1 commit into from
Closed

[WIP] Add boxed-error feature. #69

wants to merge 1 commit into from

Conversation

Yamakaky
Copy link
Contributor

Downside : the type inference for chain_err is even stricter...

@Yamakaky
Copy link
Contributor Author

Works now, just have to fix the name for Inner.

@Yamakaky
Copy link
Contributor Author

Any idea about how to handle Inner? Ideally, it's name would be generated, but rust macros don't seem to support it.

@colin-kiegel
Copy link

colin-kiegel commented Nov 24, 2016

@Yamakaky I am not 100% sure why you need the outer newtype tuple struct. Is it due to conflicting implementations on Box<E: Error>?

If this cannot be avoided I see three options:

a) wait until macros 1.1 is stable (which may even happen in the upcoming release if I read some comments correctly)
b) alternatively you could try namespacing like this - but it may hurt the ergonomics:

pub mod $error_name {
    pub struct Inner;
    pub struct Outer;
}
pub mod $error_name2 {
    pub struct Inner;
    pub struct Outer;
}

instead of

pub struct Inner;
pub struct $error_name;
pub struct Inner; // conflict with previous definition
pub struct $error_name2;

c) or last but not least, you could do some really crazy macro hacking like this until macros 1.1 are stable (that actually works)

macro_rules! pop_unique_struct {
    ($body:tt) => {
        pop_unique_struct_and_save!{
            $body
            Inner1
            Inner2
            Inner3
            Inner4
            Inner5
        }
    }
}


macro_rules! pop_unique_struct_and_save {
    ($captured_body:tt $ident:tt $( $tail:tt )*) => {
        pub struct $ident $captured_body
        macro_rules! pop_unique_struct {
            ($body:tt) => {
                pop_unique_struct_and_save!{
                    $body
                    $( $tail )*
                }
            }
        }
    }
}

pop_unique_struct!{{ foo: u32 }}
pop_unique_struct!{{ bar: u32 }}
pop_unique_struct!{{ baz: u32 }}


fn main() {
    let x1 = Inner1 { foo: 1 };
    let x2 = Inner2 { bar: 1 };
    let x3 = Inner3 { baz: 1 };
}

PS: That last approach obviously only works for a finite amount of invocations...

@Yamakaky
Copy link
Contributor Author

OMG what is this madness XD
I use the wrapper approach because it was easier, only ChainedError::new needs conditional compilation.

@colin-kiegel
Copy link

Yeah, I know it's quite ugly, but it works. ^^

The thing is you can't use macros in identifyer position yet. So if you need varying identifiers in the macro expansion, these must be fed into the macro invocation first. This trick uses higher order macros (macros defined by macros) to manage something like a global state and feed varying identifiers back into another macro. It's quite some madness indeed. If you want to go this route you'll probably need to store the last used identifier in a higher order macro, so you can still access it. That's definitely doable and I could help you. But it'll not be clean code in the sense of easily understandable.

Off topic: If you want to see some more pushing the limits with higher order macro trickery you may want to check out my proof of concept to boost the macro recursion limit exponentially with HOMs and macro callbacks: https://github.com/colin-kiegel/enum-transform/blob/tailcall_optimization/src/tailcall_optimization.rs

But back to your topic: avoiding the wrapper with conditional compilation might be the simplest approach if you don't run into overlapping implementations you don't want.

@Yamakaky
Copy link
Contributor Author

Yeah, conditional compilation is simpler than meta-macros XD.
So you think I should go for Result<T, Box<E>>?

@colin-kiegel
Copy link

Yes I would try Result<T, Box<E>>. However I am not 100% if you will run into problems with some of the magic of Box like auto-deref and all the trait implementations like impl<T: Error> Error for Box<T>. You'll have to try if that really works or turns out to be a dead end.

If you fear too much boilerplate duo to conditional compilation, then maybe you can abstract it away like this:

#[cfg(feature = "boxed-error")]
mod boxed_error {
    pub type Box<T> = ::std::boxed::Box<T>;
    pub fn new<T>(t: T) -> ::std::boxed::Box<T> { ::std::boxed::Box::new(t) }
}

#[cfg(not(feature = "boxed-error"))]
mod boxed_error {
    pub type Box<T> = T;
    pub fn new<T>(t: T) -> T { t }
}

You can then always use boxed_error::new(), boxed_error::Box<T> and maybe 1-2 additional abstractions. This way you should not need conditional compilation anywhere else. How does that sound?

@colin-kiegel
Copy link

Hm, on second thought using macros will likely interfere with this abstraction idea unless it is imported into the scope of the macro invocation. So maybe this abstraction is not such a good idea.. I am not sure.

@lilianmoraru
Copy link

macros 1.1 is out now.
@Yamakaky Don't you think that it should be a default feature? The current performance impact seems like a serious issue.

@Yamakaky
Copy link
Contributor Author

What do you mean by default feature? Boxed errors?

@lilianmoraru
Copy link

@vi
Copy link

vi commented Aug 28, 2017

Is this pull request abandoned? Will error-chain keep on inviting bloatware?

@Yamakaky
Copy link
Contributor Author

Yamakaky commented Sep 1, 2017

What do you mean?

@vi
Copy link

vi commented Sep 1, 2017

@Yamakaky, What is the status of boxed errors feature of error-chain? This pull request remains open, but inactive, conflicted and with failed checks for about 3 months, leaving uncertainity about the future of the feature.

@Yamakaky
Copy link
Contributor Author

Closed by #225

@Yamakaky Yamakaky closed this Oct 11, 2017
@Yamakaky Yamakaky deleted the boxed-error branch October 11, 2017 21:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants