Functions that may or may not take an argument - rust

I'm designing an API and I currently wish to have a function that may or may not accept an argument with default behavior for empty arguments. Using enums works ok, but that requires the user to enter certain arguments which will add up quickly. My current implementation is this:
enum ArgType {
Square,
Circle,
Triangle,
}
fn draw_image(arg: ArgType) {
match arg {
ArgType::Square => println!("Square!"),
ArgType::Circle => println!("Circle!"),
ArgType::Triangle => println!("Triangle!"),
_ => println!("Empty argument, initiating default behavior!"),
}
}
fn main() {
let circle = ArgType::Triangle;
draw_image(Triangle);
draw_image(); // Does not compile
}

You could use an Option<T>.
fn draw_image(arg: Option<ArgType>) {
match arg.unwrap_or(ArgType::DefaultArgType) {
ArgType::Square => println!("Square!"),
ArgType::Circle => println!("Circle!"),
ArgType::Triangle => println!("Triangle!"),
}
}
//...
draw_image(Some(ArgType::Circle));
draw_image(None); // will use the default ArgType
If you don't want to use a default ArgType, but instead want a completely separate functionality, I'd just define another function that immediately invokes the default behaviour.
fn draw_image_default() {
//...
}

What you are describing is a functionality called "function overloading".
Rust explicitely does not allow that. A longer discussion about the reasoning behind it can be found here.
As a direct alternative, you can represent optional parameters via the Option type. It can either be Some(value) or None.
With it, your code would look like this:
pub enum ArgType {
Square,
Circle,
Triangle,
}
fn draw_image(arg: Option<ArgType>) {
match arg {
Some(ArgType::Square) => println!("Square!"),
Some(ArgType::Circle) => println!("Circle!"),
Some(ArgType::Triangle) => println!("Triangle!"),
None => println!("Empty argument, initiating default behavior!"),
}
}
fn main() {
let triangle = ArgType::Triangle;
draw_image(Some(triangle));
draw_image(None);
}
Triangle!
Empty argument, initiating default behavior!

As others have said, function overloading is not possible in Rust and you can use Option to represent optional parameters. However this can be unwieldy if you have a lot of parameters and you expect that your users will only use a few at a time. In that case, typing all the None values for the other parameters can be quite tedious. In order to avoid that you can use the builder pattern, where you initialize a struct with the default values, then call methods to set the parameters you want and have an execute method to do the work:
#[derive (Debug)]
pub enum ArgType {
Default,
Square,
Circle,
Triangle,
}
#[derive (Debug)]
pub enum ArgColor {
Default,
White,
Black,
}
pub struct ImageDraw {
ty: ArgType,
col: ArgColor,
// ...
}
impl ImageDraw {
fn default() -> Self {
ImageDraw { ty: ArgType::Default, col: ArgColor::Default, /* ... */ }
}
fn with_type (self, ty: ArgType) -> Self {
ImageDraw { ty, ..self }
}
fn with_color (self, col: ArgColor) -> Self {
ImageDraw { col, ..self }
}
fn draw (self) {
println!("Drawing {:?} in {:?}", self.ty, self.col);
}
}
fn main() {
ImageDraw::default()
.with_type (ArgType::Triangle)
.with_color (ArgColor::White)
.draw();
ImageDraw::default()
.with_type (ArgType::Circle)
.draw();
ImageDraw::default()
.with_color (ArgColor::Black)
.draw();
}
Playground

Related

Looking for a better design pattern for methods of enums in Rust

I need a way to put different objects that all implement a certain trait integrate() in one enum. This enum shall implement a method that calls its variant's method integrate() in a certain way e.g. many times.
I tried to make a very simple example, but it is still not as short as I would want it to be.
Some more explanation: I want to write a solver that integrates certain differential equations i.e. calculate how a physical system behaves over a certain time span. For each time step the method integrate() is called. But when I execute the program I want to be able to choose which physical system is used at runtime. My idea was to have an enum that has the different physical systems in it e.g. OscillatorA and OscillatorB (in reality this could be a double pendulum, or a vibrating string - doesn't matter).
pub trait Integrate {
fn integrate(&mut self);
}
pub struct OscillatorA {
z: u32,
}
impl Integrate for OscillatorA {
fn integrate(&mut self) {
self.z += 1; // something happens here
}
}
#[derive(Debug)]
pub struct OscillatorB {
x: u32,
y: u32,
}
impl Integrate for OscillatorB {
fn integrate(&mut self) {
self.x += 1; // something different happens here
self.y += 2;
}
}
#[derive(Debug)]
pub enum Oscillator {
A(OscillatorA),
B(OscillatorB),
// ... many other physical systems come here
}
impl Oscillator {
pub fn new(num: &u64) -> Self {
match num {
0 => Self::A(OscillatorA { z: 1 }),
1.. => Self::B(OscillatorB { x: 1, y: 2 }),
}
}
}
impl Integrate for Oscillator {
fn integrate(&mut self) {
// this looks like it should be redundant:
match self {
Self::A(osc) => osc.integrate(),
Self::B(osc) => osc.integrate(),
}
}
}
pub fn integrate_n_times(object: &mut impl Integrate, n: u64) {
for _ in 0..n {
object.integrate();
}
}
fn main() {
let which = 0; // can be set via commandline arguments.
let mut s = Oscillator::new(&which);
integrate_n_times(&mut s, 10);
// ..
}
The function integrate_n_times(&mut self, n) will call n times the integrate() method required by the Integrate-trait. But it somehow doesn't feel right, because it will at each iteration solve a match-statement. I guess with compiler optimizations this might be avoided, but it somehow "feels" wrong, because it certainly reads like this.
Is there a better design pattern I am missing? Should I require the method "integrate_n_times" through the trait as well? (But then I would rely on it being written correctly in every Oscillator struct).
I somehow need to have one "main-struct" that I contains all the different physical systems and can call them depending on what arguments I pass to the program.
I would probably use dynamic dispatch here. While it's generally slower than using static dispatch, I would imagine it's faster than a massive match cases. Plus I think it's easier to work with, as long as we don't try to get the original type with Any and down-casting.
impl Oscillator {
pub fn new(num: &u64) -> Box<dyn Integrate> {
match num {
0 => Box::new(OscillatorA { z: 1 }),
1.. => Box::new(OscillatorB { x: 1, y: 2 }),
}
}
}
pub fn integrate_n_times(object: &mut Box<dyn Integrate>, n: u64) {
for _ in 0..n {
object.integrate();
}
}
fn main() {
let which = 0; // can be set via commandline arguments.
let mut my_oscillator: Box<dyn Integrate> = Oscillator::new(&which);
integrate_n_times(&mut my_oscillator, 10);
}

How can I easily get a reference to a value after it has been moved into a tuple-type enum variant?

I want to move a value into a tuple-type enum variant and obtain a reference to the value after it has been moved. I see how this is possible with an if let statement, but this seems like this should be unnecessary when the particular variant is known statically.
Is there any way to get the reference to the moved value without requiring an if let or match?
This code block is a simple illustration of my question (see below for a more challenging case):
enum Transport {
Car(u32), // horsepower
Horse(String), // name
}
fn do_something(x: &String) {
println!(x);
}
fn main() {
// Can I avoid needing this if, which is clearly redundant?
if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
do_something(name);
}
else {
// Can never happen
}
// I tried the following, it gives:
// "error[E0005]: refutable pattern in local binding: `Car(_)` not covered"
let Transport::Horse(ref name) = Transport::Horse("daisy".into());
}
It is easy to find ways to side-step the issue in the above code, since there are no real interface requirements. Consider instead the following example, where I am building a simple API for building trees (where each node can have n children). Nodes have an add_child_node method returning a reference to the node that was added, to allow chaining of calls to quickly build deep trees. (It is debatable whether this is a good API, but that is irrelevant to the question). add_child_node must return a mutable reference to the contents of an enum variant. Is the if let required in this example (without changing the API)?
struct Node {
children: Vec<Child>,
// ...
}
enum Child {
Node(Node),
Leaf
}
impl Node {
fn add_child_node(&mut self, node: Node) -> &mut Node {
self.children.push(Child::Node(node));
// It seems like this if should be unnecessary
if let Some(&mut Child::Node(ref mut x)) = self.children.last() {
return x;
}
// Required to compile, since we must return something
unreachable!();
}
fn add_child_leaf(&mut self) {
// ...
}
}
No. You can use unreachable!() for the else case, and it's usually clear even without message/comment what's going on. The compiler is also very likely to optimize the check away.
If the variants have the same type you can implement AsRef and use the Transport as a &str:
enum Transport {
Car(String),
Horse(String),
}
fn do_something<S: AsRef<str>>(x: &S) {
println!("{}", x.as_ref());
}
impl AsRef<str> for Transport {
fn as_ref(&self) -> &str {
match self {
Transport::Car(s) => s,
Transport::Horse(s) => s,
}
}
}
fn main() {
let transport = Transport::Horse("daisy".into());
do_something(&transport)
}
Playground
Otherwise you need to use a let if binding as you are doing. No need to use an else clause if you don't want to:
if let Transport::Horse(ref name) = Transport::Horse("daisy".into()) {
do_something(name);
}
define From<Transport> for String:
…
impl From<Transport> for String {
fn from(t: Transport) -> String {
match t {
Transport::Car(value) => value.to_string(),
Transport::Horse(name) => name,
}
}
}
fn do_something(x: Transport) {
println!("{}", String::from(x));
}
fn main() {
let horse = Transport::Horse("daisy".to_string());
let car = Transport::Car(150);
do_something(horse);
do_something(car);
}

rust extend built-in enum Result?

tl;dr Is it possible to extend std::result::Result to add my own variant that signals "things are Okay but also..." and keep impl Result methods like is_ok()?
I want to extend Result to signal additional states that a function caller can use for special cases.
use std::result::Result
use std::io::Error;
/// Extend Result to also signal "things are okay but check on things"
enum ResultExt<T, E> {
Result<T, E>,
OkButCheckThings(T),
}
pub fn do_stuff() -> ResultExt<u64, Error> {
// ...
}
pub fn main() -> {
let var = match do_stuff() {
Ok(val) => { val },
Err(err) => { 0 },
OkButCheckThings(val) => { check_things(); val },
}
dbg!(var);
}
It's possible to plainly extend an Enum. But I would also like to use the underlying Result<T, E> functions like is_ok.
let var2 = do_stuff();
if var2.is_ok() {
println!("It is totally Ok, nothing to check!");
}
I created a rust playground example that successfully extends Result<T, E> but the extended enum cannot use functions like is_ok().
The real-world use-case is a function that calls std::io::Read may need to "modify" the returned Result to signal additional states beyond Ok and Err. But I want these various "meta states" to be captured by one enum, as opposed to returning various other bool flags (I want to avoid return signature with (Result<T>, bool, bool). This would allow one clean match statement of all possible states; Ok, Err, "Okay but...", "Err but ...", etc..
There is no current way of "extending" and enum perse.
But it could be simply solved by embedding your own enum type into the result itself.
Simple example, similar to yours:
use std::fmt::Display;
enum StuffToCheck<T> {
Ok(T),
CheckThis(T),
}
impl<T> StuffToCheck<T>
where
T: Display + Copy,
{
pub fn check_things(&self) -> T {
match self {
Self::Ok(val) => {
*val
}
Self::CheckThis(val) => {
println!("Checking stuff for {}", val);
*val
}
}
}
}
fn do_stuff() -> ResultExt<u64> {
Ok(StuffToCheck::CheckThis(10))
}
type ResultExt<T> = Result<StuffToCheck<T>, std::io::Error>;
fn main() {
let var = match do_stuff() {
Ok(result) => result.check_things(),
Err(_err) => 0,
};
dbg!(var);
}
Playground
You could even use nested pattern matching:
...
match do_stuff() {
Err(e) => {//handle error}
Ok(StuffToCheck::Ok(value)) => { value },
Ok(StuffToCheck::CheckThis(value)) => {
check_things(value);
value
}
}
...
I think this is an instance of the X-Y problem. You can use the built-in result, you just need a different error type, that returns an option: Some(partial_result) or None.
For example you have function parse, that can attempt to adjust for a malformed input, but report the error.
pub fn parse(b: &str) -> Result<&str, CustomParseError> {
// Do something that might fail,
if failed(){
return CustomParseError::new(None)
} else if partially_failed() {
return CustomParseError::new(Some(partial_result))
} else {
return completeResult
}
}
This way you have a clean code path where nothing failed, and all of your assumptions are correct, and if it's not => instead of unwrapping, you match and check which case you have. This is vastly superior, because the error often contains enough information for you to reconstruct both what went wrong, and what could be done to fix it.

How to implement callback on typing in textbox with rust druid (not lens, but a method call)?

I want to call the following method with arguments, either by passing them or from a closure:
fn set_border(&mut self, arg: &str, is_left_border: bool) -> () {
let val = arg.parse::<f64>();
match val {
Ok(float) => { if is_left_border {self.left_border = Some(float)} else {self.right_border = Some(float)}},
Err(_) => {}
}
}
when text is entered to the textbox. I didn't find a way to use lens to access methods, but I'm quite new to rust and decided to ask for advice.
As far as I'm concerned if I can "track" changes of the field and do it that way it will also do.
Thanks in advance.
You can use a Controller to be called when the TextBox receives a call to its update method and then check whether the data has changed:
use druid::{
AppLauncher,
WidgetExt,
Widget,
Env,
UpdateCtx,
WindowDesc,
widget::TextBox,
widget::Controller
};
struct UpdateCallback();
impl Controller<String, TextBox<String>> for UpdateCallback {
fn update(&mut self,
child: &mut TextBox<String>,
ctx: &mut UpdateCtx<'_, '_>,
old_data: &String,
data: &String,
env: &Env
) {
if old_data != data {
// the data has changed, you can call your function here
println!("{}", data);
}
// also inform the child that the data has changed
child.update(ctx, old_data, data, env)
}
}
fn build_root_widget() -> impl Widget<String> {
TextBox::new().controller(UpdateCallback())
}
fn main() {
AppLauncher::with_window(WindowDesc::new(build_root_widget)).launch("Test".to_string()).unwrap();
}
The relevant part here is the Controller impl for UpdateCallback as well as the call to controller() inside the build_root_widget() function.

How to check arg type inside a macro_rule? [duplicate]

This is just pseudocode:
macro_rules! attribute {
$e: expr<f32> => { /* magical float stuff */ };
$e: expr<i64> => { /* mystical int stuff */ };
};
I would like to have a differently expanded macro depending on the type that I passed to the macro.
This is how it would work in C++
template <typename T>
struct Attribute{ void operator(T)() {} };
template <>
struct Attribute<float> {
void operator(float)(float) { /* magical float stuff */ }
};
template <>
struct Attribute<long> {
void operator()(long) { /* mystical int stuff */ }
}
Rust macros aren't able to do that. Macros operate at the syntactic level, not at the semantic level. That means that although the compiler knows it has an expression (syntax), it doesn't know what the type of the expression's value (semantic) is at the moment the macro is expanded.
A workaround would be to pass the expected type to the macro:
macro_rules! attribute {
($e:expr, f32) => { /* magical float stuff */ };
($e:expr, i64) => { /* mystical int stuff */ };
}
fn main() {
attribute!(2 + 2, i64);
}
Or, more simply, define multiple macros.
If you want to do static (compile-time) dispatch based on the type of an expression, you can use traits. Define a trait with the necessary methods, then implement the trait for the types you need. You can implement a trait for any type (including primitives and types from other libraries) if the impl block is in the same crate as the trait definition.
trait Attribute {
fn process(&self);
}
impl Attribute for f32 {
fn process(&self) { /* TODO */ }
}
impl Attribute for i64 {
fn process(&self) { /* TODO */ }
}
macro_rules! attribute {
($e:expr) => { Attribute::process(&$e) };
}
fn main() {
attribute!(2 + 2);
}
Note: You could also write $e.process() in the macro's body, but then the macro might call an unrelated process method.
As already explained, you cannot expand differently depending on the type of an expr. But as a workaround, you can use the any module and try to downcast from the Any trait:
use std::any::Any;
macro_rules! attribute {
( $e:expr ) => {
if let Some(f) = (&$e as &Any).downcast_ref::<f32>() {
println!("`{}` is f32.", f);
} else if let Some(f) = (&$e as &Any).downcast_ref::<f64>() {
println!("`{}` is f64.", f);
} else {
println!("I dunno what is `{:?}` :(", $e);
}
};
}
fn main() {
attribute!(0f32);
attribute!(0f64);
attribute!(0);
}
Displays:
`0` is f32.
`0` is f64.
I dunno what is `0` :(
While all the answers here are correct, I'd like to provide an answer more akin to your C++ version.
Rust provides its own version of templates, generics, and they can be used in the same way you use templates.
So, to define a struct and implement functions for certain types:
struct Attribute<T> {
value: T,
}
impl Attribute<u32> {
fn call(&self) {
println!("{} is a u32", self.value);
}
}
impl Attribute<f64> {
fn call(&self) {
println!("{} is a f64", self.value);
}
}
impl Attribute<String> {
fn call(&self) {
println!("{} is a string", self.value);
}
}
We'd use it like that:
fn main() {
let a = Attribute{
value: 5_u32
};
a.call();
}
Or simply like this:
Attribute{value: 6.5}.call()
Sadly, Rust doesn't provide () operator overloading in its stable version. You can still define a macro to do the job:
macro_rules! attribute {
( $e:expr ) => {
Attribute{value: $e}.call();
};
}
And use it as so:
attribute!("Hello World!".to_string());
I'd recommend using the trait based approach shown in this answer, as it doesn't use a struct, but a trait, which is considered better practice. This answer may still be helpful in many situations.

Resources