Skip to content

Remove the various Default traits#289

Merged
bors[bot] merged 2 commits into
rust-embedded:masterfrom
lachlansneff:remove-default
Jul 20, 2021
Merged

Remove the various Default traits#289
bors[bot] merged 2 commits into
rust-embedded:masterfrom
lachlansneff:remove-default

Conversation

@lachlansneff

Copy link
Copy Markdown
Contributor

As discussed in the embedded-hal meeting, the default traits and their corresponding impls interfere with upstream implementations.

The Default traits and their corresponding impls interfered with upstream implementations
@lachlansneff lachlansneff requested a review from a team as a code owner June 29, 2021 19:27
@rust-highfive

Copy link
Copy Markdown

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @ryankurte (or someone else) soon.

Please see the contribution instructions for more information.

@GrantM11235

Copy link
Copy Markdown
Contributor

Here is the example that I brought up in the meeting:

struct GenericSpiDevice<W>(core::marker::PhantomData<W>);

impl<W> embedded_hal::blocking::spi::Write<W> for GenericSpiDevice<W> {
    type Error = ();
    fn write(&mut self, _: &[W]) -> Result<(), Self::Error> {
        todo!()
    }
}
error[E0119]: conflicting implementations of trait `embedded_hal::prelude::_embedded_hal_blocking_spi_Write<_>` for type `GenericSpiDevice<_>`:
 --> src/lib.rs:3:1
  |
3 | impl<W> embedded_hal::blocking::spi::Write<W> for GenericSpiDevice<W> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `embedded_hal`:
          - impl<W, S> _embedded_hal_blocking_spi_Write<W> for S
            where S: embedded_hal::blocking::spi::write::Default<W>, W: Clone;
  = note: downstream crates may implement trait `embedded_hal::blocking::spi::write::Default<_>` for type `GenericSpiDevice<_>`

I don't think that embedded_hal::blocking::digital::toggleable::Default causes the same problem because it doesn't have a generic type parameter.

@burrbull

Copy link
Copy Markdown
Member

I don't understand how they can interfere.
Does GenericSpiDevice<W> implement Default<W>?

@GrantM11235

Copy link
Copy Markdown
Contributor

That took me a while to figure out too. Apparently, a downstream crate foo with a type Bar could impl embedded_hal::blocking::spi::write::Default<foo::Bar> for GenericSpiDevice<foo::Bar>.

@burrbull

Copy link
Copy Markdown
Member

That took me a while to figure out too. Apparently, a downstream crate foo with a type Bar could impl embedded_hal::blocking::spi::write::Default<foo::Bar> for GenericSpiDevice<foo::Bar>.

Just delete this impl.

@GrantM11235

GrantM11235 commented Jun 30, 2021

Copy link
Copy Markdown
Contributor

That is a hypothetical impl, it doesn't exist. The mere fact that it could exist (in a different crate) is enough for rustc to forbid impl<W> embedded_hal::blocking::spi::Write<W> for GenericSpiDevice<W>.

@ryankurte

ryankurte commented Jul 5, 2021

Copy link
Copy Markdown
Contributor

ahh i've been caught by this before, you can avoid the problem by removing the generic over word length and implementing over concrete u8/u16/whatever:

struct GenericSpiDevice<W>(core::marker::PhantomData<W>);

impl embedded_hal::blocking::spi::Write<u8> for GenericSpiDevice<u8> {
    type Error = ();
    fn write(&mut self, _: &[u8]) -> Result<(), Self::Error> {
        todo!()
    }
}

impl embedded_hal::blocking::spi::Write<u16> for GenericSpiDevice<u16> {
    type Error = ();
    fn write(&mut self, _: &[u16]) -> Result<(), Self::Error> {
        todo!()
    }
}

in practice you usually can't do much with the generic trait as they're not object-safe so you'll basically always need to take this approach anyway, does that solve your issue?

@GrantM11235

Copy link
Copy Markdown
Contributor

My earlier example is a bit contrived, what I was actually trying to do is create an adapter that takes a blocking::spi::Write and implements blocking::spi::WriteIter.

I could copy-paste or use a macro to impl this separately for u8 and u16, but that would mean that my adapter wouldn't work for 9-bit words for example.

In my opinion there are also other good reasons to remove the default trait markers before v1.0. The way they are implemented is confusing and feels like a hack, and they only save the HALs from having to write a few lines of trivial code.

@eldruin

eldruin commented Jul 13, 2021

Copy link
Copy Markdown
Member

FWIW, I'm fine with removing the default impls. As commented here and elsewhere, they add little value, can be slightly problematic as commented above and assume nb as the "main" traits, which we will deprecate at some point.

@Dirbaio

Dirbaio commented Jul 13, 2021

Copy link
Copy Markdown
Member

I'm in favor of removing the Default traits, even if the above mentioned conflicting impl issues can be worked around.

  1. It establishes the nb traits as the True Traits and the blocking traits as derived ones. It encourages HAL writers to impl only the nb traits and base everything off that. nb is incompatible with lots of nice stuff, such as DMA impls. We might even want to deprecate nb in the future.
  2. It doesn't make for very nice docs. Example. Ideally that should show Spi impls embedded_hal::blocking::spi::Transfer, but it doesn't. The Default implementation detail leaks to the end user.

Comment thread CHANGELOG.md Outdated
Co-authored-by: GrantM11235 <GrantM11235@gmail.com>

@therealprof therealprof left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, thanks.

bors r+

@bors

bors Bot commented Jul 20, 2021

Copy link
Copy Markdown
Contributor

@bors bors Bot merged commit 7f3801e into rust-embedded:master Jul 20, 2021
timokroeger added a commit to timokroeger/embedded-can that referenced this pull request Sep 22, 2021
Dirbaio added a commit to Dirbaio/embedded-hal that referenced this pull request Nov 3, 2021
These were removed in rust-embedded#289 but
the doc comments were not updated accordingly.
bors Bot added a commit that referenced this pull request Nov 3, 2021
322: Remove docs mentioning the Default marker traits. r=ryankurte a=Dirbaio

These were removed in #289 but
the doc comments were not updated accordingly.

Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Review is incomplete T-hal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants