# Idea: Conditional code based on whether a type implements a trait

**URL:** <https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696>\
**Category:** language design\
**Created:** [December 1, 2021, 8:23am UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696 "2021-12-01T08:23:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![KSXGitHub](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ksxgithub/32/5582_2.png) [@KSXGitHub](https://internals.rust-lang.org/u/KSXGitHub)\
**Post date:** [December 1, 2021, 8:23am UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/1 "2021-12-01T08:23:03Z")

</div>

## The problem I faced

I sometimes want to log values inside a generic function, but can't, because the type does not have `std::fmt::Debug` as a trait constraint. This means that I have to either add a trait constraint or give up.

## Proposal

I wish there was a mechanism that allow me to use `std::fmt::Debug` without having to add it as a trait constraint. For example:

```rust
fn do_something<X>(x: &mut X) {
  transform1(x);
  if X impl std::fmt::Debug {
    eprintln!("after transform1: {:?}", x);
  }
  transform2(x);
  if X impl std::fmt::Debug {
    eprintln!("after transform2: {:?}", x);
  }
}

```

* * *

**P.S.** This is just an idea open for discussion. I don't intend on writing an RFC myself.

---

<div class="post-metadata">

**Author:** ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)\
**Post date:** [December 1, 2021, 8:30am UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/2 "2021-12-01T08:30:36Z")

</div>

This would be covered by specialization, no?

---

<div class="post-metadata">

**Author:** ![KSXGitHub](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ksxgithub/32/5582_2.png) [@KSXGitHub](https://internals.rust-lang.org/u/KSXGitHub)\
**Post date:** [December 1, 2021, 8:49am UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/3 "2021-12-01T08:49:56Z")

</div>

Do you have link to "specialization"? Anyway, before reading it, I guess that it would be more complicated than an `if` statement.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [December 1, 2021, 8:57am UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/4 "2021-12-01T08:57:17Z")

</div>

> [@KSXGitHub](#):
>
> I sometimes want to log values inside a generic function, but can't, because the type does not have `std::fmt::Debug` as a trait constraint.

I suggest you check out this thread from a few days ago:

> [@Pre-RFC: MaybeDebug\<T\> type which always \`impl Debug\`](https://internals.rust-lang.org/t/pre-rfc-maybedebug-t-type-which-always-impl-debug/15670):
>
> Please let me know what you're thinking about it. Also, should I keep the empty sections on real RFC? Summary Adds struct MaybeDebug\<T\>(&T);. which implements Debug trait regardless whether the T implements it. Motivation Debug trait is used for the programmer-facing, debugging context formatting. Most public types implements this trait to enable casual debugging. But since it's a regular trait not something built into the language, you need to explicitly adds trait bound to use it in the ge…

---

<div class="post-metadata">

**Author:** ![VorfeedCanal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/vorfeedcanal/32/8797_2.png) [@VorfeedCanal](https://internals.rust-lang.org/u/VorfeedCanal)\
**Post date:** [December 5, 2021, 1:27pm UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/5 "2021-12-05T13:27:26Z")

</div>

> [@KSXGitHub](#):
>
> Anyway, before reading it, I guess that it would be more complicated than an `if` statement.

I think you are forgetting something important: complexity has to live somewhere.

Typically “simple and obvious” features are, in reality, harder to implement than features which look, superficially, more complex.

What you are asking for is, essentially, [if constexpr](https://en.cppreference.com/w/cpp/language/if) from C++.

And if constexpr is, of course, harder to properly design and implement than specialization.

In fact if constexpr is built on top of machinery designed for template specialization support. And it was only added in C++17 in spite of the fact that template specialization was in C++98 already (although it took years to iron out bugs in the implementation).

Note that if constexpr is, actually, a minor complication over the specialization, the main complexity lies in the specialization machinery. But I don't think anyone would seriously consider it till specialization issues would be ironed out one way or another.

It may not be obvious to you just **why** your simple idea is quite complicated. But consider something like this:

```rust
fn do_something<X>(x: &mut X) {
  let mut log;
  if X impl std::fmt::Debug {
    log = fmt!("{:?}", x);
  }
  transform(x);
  if X impl std::fmt::Debug {
    eprintln!("transformed {} to {:?}", log, x);
  }
}

```

Is this valid code or not? What about this:

```rust
fn do_something<X>(x: &mut X) {
  let mut log;
  if X impl std::fmt::Debug {
    log = fmt!("{:?}", x);
  } else {
    log = 42;
  }
  transform(x);
  if X impl std::fmt::Debug {
    eprintln!("transformed {} to {:?}", log, x);
  }
}

```

What would happen if you are dozen of checks? To understand if your code is valid or not without exploring all the possibilities (which would lead to exponential compilation times because of combinatorial explosion) you would need some quite complicated machinery.

Thankfully it's pretty similar to what specialization already have to do and would, probably, be able to reuse some of the same machinery, but… such feature is, most definitely, harder to properly define and implement than specialization.

But sure, it's much easier to use. `if constexpr` made metaprogramming much more popular in C++ world. Because it become easier to implement simple things. But there are still a lot of issues related to it in the major C++ compilers.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 5, 2022, 1:28pm UTC](https://internals.rust-lang.org/t/idea-conditional-code-based-on-whether-a-type-implements-a-trait/15696/6 "2022-03-05T13:28:09Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
