# Way to obtain \`Option\<fn(...)\>\` from traits if the function is not implemented

**URL:** <https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727>\
**Category:** language design\
**Created:** [November 11, 2022, 1:05am UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727 "2022-11-11T01:05:00Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![tgross35](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tgross35/32/9550_2.png) [@tgross35](https://internals.rust-lang.org/u/tgross35)\
**Post date:** [November 11, 2022, 1:05am UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/1 "2022-11-11T01:05:00Z")

</div>

Has there been any thought about a way to get a nullable function pointer if a trait member function is unimplemented?

This would be relevant for interfacing with C libraries, where structs of functions are used as vtables - especially relevant when one might want to write a plugin or module in Rust. As an example, a C interface might expect the following vtable for an interface:

```rust
#[repr(C)]
pub struct st_operation{
    pub init: Option<unsafe extern "C" fn(self_: *mut c_void) -> c_int>,
    pub calc: Option<unsafe extern "C" fn(self_: *mut c_void, val: c_int) -> c_int>,
    pub deinit: Option<unsafe extern "C" fn(self_: *mut c_void) -> c_int>,
    ...
}

```

Logically, these map well to a Rust trait, which might look like the following:

```rust
trait Operation {
    fn init() -> Result<Self, ()>;
    
    #[detectable_unimplemented]
    fn calc(&mut self, val: i32) -> Result<(), ()> {
        unimplemented!()
    }
    
    fn deinit(&mut self) -> Result<(), ()>;
}

```

The thought was that `#[unimplemented_nullptr]` would be used to indicate that if that member function is not overridden when `impl`'d, it should be possible to know this when trying to get a function pointer.

```rust
// Will be a function pointer to that method if it's implemented, None otherwise
let x: Option<_> somestruct.calc.as_option()

```

The crate [`vtable`](https://docs.rs/vtable/latest/vtable/) provides some of this functionality, but it isn't always suitable. Rust for linux uses a custom `vtable` macro ([source](https://github.com/Rust-for-Linux/linux/blob/729c03011c60382030520f84904a85e8a5b3cfb9/rust/macros/vtable.rs), [trait](https://rust-for-linux.github.io/docs/kernel/file/trait.Operations.html) and [usage example](https://github.com/Rust-for-Linux/linux/blob/729c03011c60382030520f84904a85e8a5b3cfb9/samples/rust/rust_chrdev.rs#L18))

Is there any chance a smoother implementation possibility would be considered for Rust?

---

<div class="post-metadata">

**Author:** ![197g](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/197g/32/7276_2.png) [@197g](https://internals.rust-lang.org/u/197g)\
**Post date:** [November 11, 2022, 6:43pm UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/2 "2022-11-11T18:43:00Z")

</div>

What are some shortcomings of the Linux kernel macro and how do you wish to address them with that proposed language attribute? I don't immediately see how it would be feasible to produce the value you desire. What is the exact type you would expect in `let x: Option<_>`? The function zst object, a function pointer of the concrete class, or a function pointer of `&mut dyn Operation`? The largest hurdle is that the usual unsized trait objects vtables only contain functions pointers and their attributes aren't accessible directly–only via `dyn Operation` values, which wouldn't exist in your example since `fn init()` make the trait non-object-safe as far as I can tell.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [November 11, 2022, 7:46pm UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/3 "2022-11-11T19:46:16Z")

</div>

The more Rust-idiomatic interface would be to just provide a default implementation and the vtable always contain a valid pointer, rather than have a nullable pointer in the vtable and (presumably) branching on null to do some default handling.

There is unfortunately a slight code size penalty for this unless the optimizer manages to polymorphize the implementation.

If you do actually need properly optional methods, the ideal post-expansion interface would probably look something like

```rust
trait Operation: ErasePtr {
    fn new() -> my::Result<Self>;
    fn flush(&mut self) -> my::Result<()>;

    const fn#calc: Option<fn(&mut Self, i32) -> my::Result<()>> = {
        where
            const { Self::fn#calc.is_some() }
        {
            Some(Self::calc)
        } else {
            None
        }
    };

    fn calc(&mut self, val: i32) -> my::Result<()>
    where const { Self::fn#calc.is_some() };
}

```

This uses a bunch of ad-hoc imaginary features I made up just now, and contains a cycle, but I think illustrates the point.

---

<div class="post-metadata">

**Author:** ![tgross35](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tgross35/32/9550_2.png) [@tgross35](https://internals.rust-lang.org/u/tgross35)\
**Post date:** [November 11, 2022, 9:02pm UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/4 "2022-11-11T21:02:35Z")

</div>

Thanks for the replies - here's my followup:

- For shortcomings of the Linux kernel macro: it does work, but there are some uncomfortable things. The macro adds a `const USE_VTABLE_ATTR`, and a `const HAS_X` for each trait to track what is implemented. Which is OK from a functionality standpoint, but leads to a somewhat confusing API (see e.g. [`file::Operations` docs](https://rust-for-linux.github.io/docs/kernel/file/trait.Operations.html)). This macro must also be used both on the trait definition and on any corresponding `impl` block, and there is no per-field control (not that you necessarily need that, and a stronger proc macro could sense this)

- I was imagining it to be a optional function pointer to that class's implementation - so really, just a nullable function pointer. But it could be anything, even just a bool to indicate that it is or isn't implemented, as long as the result can be compile-time evaluated.

- You're correct that this example trait wouldn't work in a 1:1 way, but I was intending to have a wrapper interface. Perhaps something like the following

> The more Rust-idiomatic interface would be to just provide a default implementation and the vtable always contain a valid pointer

That does sound like a good rusty way. My concern here is that having a non-null pointer may be defined to have different behavior within the C caller, e.g. start allocating things to pass to that function's arguments, so there might be a performance hit too (maybe LTO could optimize, but that wouldn't help dynamic modules)

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [November 12, 2022, 12:18am UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/5 "2022-11-12T00:18:54Z")

</div>

In some sense trait methods are equivalent to associated const function pointers (some piece of code specified by some type when implementing some trait), so for optional methods maybe you could make the optional trait method an associated constant Option of a function pointer instead:

```rust
trait Operation {
    const CALC: Option<fn(&mut Self, i32) -> Result<(),()>> = None;
}
fn test<T: Operation>(mut x: T) {
    if let Some(f) = Operation::CALC {
        f(&mut x, 42);
    }
}

```

[full example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=800215976d54df68594821ad25b43152)

Unfortunately this won't work for trait objects since associated constants aren't object safe, but I would hope that could change in the future. It looks like the vtable-crate does allow constants.

---

<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:** [February 10, 2023, 12:19am UTC](https://internals.rust-lang.org/t/way-to-obtain-option-fn-from-traits-if-the-function-is-not-implemented/17727/6 "2023-02-10T00:19:26Z")

</div>

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