pyo3 icon indicating copy to clipboard operation
pyo3 copied to clipboard

Default values in enum struct-variants

Open EricLBuehler opened this issue 1 year ago • 4 comments

Hello everyone,

Thank you for your great work here. Our project makes extensive use of struct enum variants. However, we have many variants which should have default values: some of those variants are Option<...> and should default to None if they are not specified. This behavior would be similar to the kwargs in functions, where a default is used if the value is not specified.

Currently, for this enum:

#[pyclass]
enum Thing
  A {
    x: Option<i32>,
    y: i32,
    z: i32,
  }
}

I would use it like this: Thing.A(x=None, y=5, z=1).

However, setting x to None manually makes the code more verbose. It would be easier for the user to do the following:

#[pyclass]
enum Thing
  A {
    #[pyo3(default = None)] # <----- Add something like this?
    x: Option<i32>,
    y: i32,
    #[pyo3(default = 1)]
    z: i32
  }
}

Which would be used like this: Thing.A(y=5) where x=None and z=1.

I am not sure how difficult this is to implement, but it would be much appreciated to have this feature!

EricLBuehler avatar Apr 23 '24 10:04 EricLBuehler

How about allowing #[pyo3(signature = ...)] on complex enum variants to specify the constructor signature? Like so:

#[pyclass]
enum Thing
  #[pyo3(signature = (x = None, y = 0, z = 1)]
  A {
    x: Option<i32>,
    y: i32,
    z: i32,
  }
}

This would be comparable to building the class hierarchi manuelly and gives the same control (default, pos/kw only args, ...) as a the constructor for a #[pyclass] struct would. We would also be able to reuse the existing attribute implementation from #[pyfunction]/#[pymethods]. I've experimented with that idea over here https://github.com/Icxolu/pyo3/commit/3e2c41b377d0ed825c33b4a833b01e5aa25bb727

Icxolu avatar Apr 27 '24 14:04 Icxolu

@Icxolu, I think that looks great! Do you plan to open a PR?

EricLBuehler avatar Apr 28 '24 20:04 EricLBuehler

Thanks! Glad you like it. Yes, if people think the syntax and functionality proposed above is workable I'll open a PR from that. Given that #[pyo3(signature = ...] is currently only supported on functions (and is most intuitively understand there), I think I'll wait for a few more opinions whether we should reuse it here, or if we perhaps should rename it in this position (#[pyo3(constructor = ...)], or something like that could also be an option) to make clear what the signature refers to.

Icxolu avatar Apr 28 '24 21:04 Icxolu

I really like it too. And actually, I think it could also make sense to extend this feature to regular struct, to auto-generate constructors in a kind of dataclass-like fashion (but not necessarily in the same PR).

wyfo avatar Apr 29 '24 08:04 wyfo