How is there a conflicting implementation of `From` when using a generic type?
I'm trying to implement an error enum which can contain an error associated with one of our traits like this:
trait Storage
type Error;
enum MyError<S: Storage>
StorageProblem(S::Error),
I have also tried to implement the From
trait to allow construction of MyError
from an instance of a Storage::Error
:
impl<S: Storage> From<S::Error> for MyError<S>
fn from(error: S::Error) -> MyError<S>
MyError::StorageProblem(error)
(playground)
However this fails to compile:
error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/main.rs:9:1
|
9 | / impl<S: Storage> From<S::Error> for MyError<S>
| |_^
|
= note: conflicting implementation in crate `core`
I don't understand why the compiler reckons this has already been implemented. The error message is telling me that there's already an implementation of From<MyError<_>>
(which there is), but I'm not trying to implement that here - I'm trying to implement From<S::Error>
and MyError
is not the same type as S::Error
from what I can see.
Am I missing something fundamental to generics here?
rust
add a comment |
I'm trying to implement an error enum which can contain an error associated with one of our traits like this:
trait Storage
type Error;
enum MyError<S: Storage>
StorageProblem(S::Error),
I have also tried to implement the From
trait to allow construction of MyError
from an instance of a Storage::Error
:
impl<S: Storage> From<S::Error> for MyError<S>
fn from(error: S::Error) -> MyError<S>
MyError::StorageProblem(error)
(playground)
However this fails to compile:
error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/main.rs:9:1
|
9 | / impl<S: Storage> From<S::Error> for MyError<S>
| |_^
|
= note: conflicting implementation in crate `core`
I don't understand why the compiler reckons this has already been implemented. The error message is telling me that there's already an implementation of From<MyError<_>>
(which there is), but I'm not trying to implement that here - I'm trying to implement From<S::Error>
and MyError
is not the same type as S::Error
from what I can see.
Am I missing something fundamental to generics here?
rust
add a comment |
I'm trying to implement an error enum which can contain an error associated with one of our traits like this:
trait Storage
type Error;
enum MyError<S: Storage>
StorageProblem(S::Error),
I have also tried to implement the From
trait to allow construction of MyError
from an instance of a Storage::Error
:
impl<S: Storage> From<S::Error> for MyError<S>
fn from(error: S::Error) -> MyError<S>
MyError::StorageProblem(error)
(playground)
However this fails to compile:
error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/main.rs:9:1
|
9 | / impl<S: Storage> From<S::Error> for MyError<S>
| |_^
|
= note: conflicting implementation in crate `core`
I don't understand why the compiler reckons this has already been implemented. The error message is telling me that there's already an implementation of From<MyError<_>>
(which there is), but I'm not trying to implement that here - I'm trying to implement From<S::Error>
and MyError
is not the same type as S::Error
from what I can see.
Am I missing something fundamental to generics here?
rust
I'm trying to implement an error enum which can contain an error associated with one of our traits like this:
trait Storage
type Error;
enum MyError<S: Storage>
StorageProblem(S::Error),
I have also tried to implement the From
trait to allow construction of MyError
from an instance of a Storage::Error
:
impl<S: Storage> From<S::Error> for MyError<S>
fn from(error: S::Error) -> MyError<S>
MyError::StorageProblem(error)
(playground)
However this fails to compile:
error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:
--> src/main.rs:9:1
|
9 | / impl<S: Storage> From<S::Error> for MyError<S>
| |_^
|
= note: conflicting implementation in crate `core`
I don't understand why the compiler reckons this has already been implemented. The error message is telling me that there's already an implementation of From<MyError<_>>
(which there is), but I'm not trying to implement that here - I'm trying to implement From<S::Error>
and MyError
is not the same type as S::Error
from what I can see.
Am I missing something fundamental to generics here?
rust
rust
edited Sep 24 '17 at 0:53
Shepmaster
159k16327470
159k16327470
asked May 20 '16 at 12:54
FraserFraser
52.5k10169180
52.5k10169180
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
Specifically,
struct Tricky;
impl Storage for Tricky
type Error = MyError<Tricky>;
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky>
...
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
add a comment |
A workaround for the coherence issue is to use Result::map_err
to perform the conversion yourself. You can then use the end Result
with try!
or ?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>>
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)
This solution is also valuable when there are error variants that have the same underlying Error
, such as if you want to separate "file opening" and "file reading" errors, both of which are io::Error
.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37347311%2fhow-is-there-a-conflicting-implementation-of-from-when-using-a-generic-type%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
Specifically,
struct Tricky;
impl Storage for Tricky
type Error = MyError<Tricky>;
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky>
...
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
add a comment |
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
Specifically,
struct Tricky;
impl Storage for Tricky
type Error = MyError<Tricky>;
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky>
...
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
add a comment |
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
Specifically,
struct Tricky;
impl Storage for Tricky
type Error = MyError<Tricky>;
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky>
...
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
The problem here is someone may implement Storage
so that the From
impl you have written overlaps with the impl in the standard library of impl<T> From<T> for T
(that is, anything can be converted to itself).
Specifically,
struct Tricky;
impl Storage for Tricky
type Error = MyError<Tricky>;
(The set-up here means this doesn't actually compile—MyError<Tricky>
is infinitely large—but that error is unrelated to the reasoning about impl
s/coherence/overlap, and indeed small changes to MyError
can make it compile without changing the fundamental problem, e.g. adding a Box
like StorageProblem(Box<S::Error>),
.)
If we substitute Tricky
in place of S
in your impl, we get:
impl From<MyError<Tricky>> for MyError<Tricky>
...
This impl
exactly matches the self-conversion one with T
== MyError<Tricky>
, and hence the compiler wouldn't know which one to choose. Instead of making an arbitrary/random choice, the Rust compiler avoids situations like this, and thus the original code must be rejected due to this risk.
This coherence restriction can definitely be annoying, and is one of reasons that specialisation is a much-anticipated feature: essentially allows manually instructing the compiler how to handle overlap... at least, one of the extensions to the current restricted form allows that.
edited May 20 '16 at 13:24
answered May 20 '16 at 13:04
huonhuon
55.9k7148174
55.9k7148174
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
add a comment |
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
Has the extension been implemented in nightly now?
– WiSaGaN
May 20 '16 at 13:08
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
No, and in fact the restricted form is still available only in nightly. I believe the intention is to let that bake for a bit/iron out the bugs before diving into the more flexible/powerful versions.
– huon
May 20 '16 at 13:10
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
A clear answer: thanks. I guess the error message could be a bit clearer if it said something like there could be conflicting implementations rather than implying there already are.
– Fraser
May 20 '16 at 13:11
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
@Fraser, yeah, definitely, I guess it may be covered by github.com/rust-lang/rust/issues/23980 (I'll write a comment summarising this particular piece of confusion there).
– huon
May 20 '16 at 13:14
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
Brilliant - thanks again.
– Fraser
May 20 '16 at 13:15
add a comment |
A workaround for the coherence issue is to use Result::map_err
to perform the conversion yourself. You can then use the end Result
with try!
or ?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>>
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)
This solution is also valuable when there are error variants that have the same underlying Error
, such as if you want to separate "file opening" and "file reading" errors, both of which are io::Error
.
add a comment |
A workaround for the coherence issue is to use Result::map_err
to perform the conversion yourself. You can then use the end Result
with try!
or ?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>>
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)
This solution is also valuable when there are error variants that have the same underlying Error
, such as if you want to separate "file opening" and "file reading" errors, both of which are io::Error
.
add a comment |
A workaround for the coherence issue is to use Result::map_err
to perform the conversion yourself. You can then use the end Result
with try!
or ?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>>
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)
This solution is also valuable when there are error variants that have the same underlying Error
, such as if you want to separate "file opening" and "file reading" errors, both of which are io::Error
.
A workaround for the coherence issue is to use Result::map_err
to perform the conversion yourself. You can then use the end Result
with try!
or ?
:
fn example<S: Storage>(s: S) -> Result<i32, MyError<S>>
s.do_a_thing().map_err(MyError::StorageProblem)?;
Ok(42)
This solution is also valuable when there are error variants that have the same underlying Error
, such as if you want to separate "file opening" and "file reading" errors, both of which are io::Error
.
edited Nov 4 '17 at 15:06
answered Oct 9 '17 at 15:27
ShepmasterShepmaster
159k16327470
159k16327470
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f37347311%2fhow-is-there-a-conflicting-implementation-of-from-when-using-a-generic-type%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown