Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you share implementation details in a functional language like rust?

I sometimes find myself writing abstract classes with partial implementation in C#:

abstract public class Executor {
    abstract protected bool Before();
    abstract protected bool During();
    abstract protected bool After();
    protected bool Execute() {
         var success = false;
         if (Before()) {
              if (During()) {
                  if (After()) {
                        success = true;
                  }
              }
         }
         return success;
    }
}

Notwithstanding the wisdom of such a control structure, how would I accomplish this (partial shared implementation) in a functional language like rust?

like image 970
tacos_tacos_tacos Avatar asked Jul 08 '13 06:07

tacos_tacos_tacos


People also ask

Is Rust functional or imperative?

Rust is an imperative language, but it follows many functional programming paradigms. In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions.

Is Rust a functional or OOP?

Under this definition, then, Rust is object-oriented: structs and enums have data and impl blocks provide methods on structs and enums. Even though structs and enums with methods aren't called objects, they provide the same functionality, under the Gang of Four's definition of objects.

How do you create objects in Rust?

In rust we do not create objects itself, we call them instances. To create a instance you just use the struct name and a pair of {}, inside you put the name of the fields with values.

Does Rust support inheritance?

In Rust, there is no concept of "inheriting" the properties of a struct. Instead, when you are designing the relationship between objects do it in a way that one's functionality is defined by an interface (a trait in Rust).


2 Answers

I'm not within reach of a rust compiler, so forgive broken code.

On a functional side of things, you could make a struct that holds three functions and invoke them

struct Execution {
    before: @fn() -> bool,
    during: @fn() -> bool,
    after: @fn() -> bool
}

fn execute (e: Execution) -> bool {
  ...
}

but once you have a function as a first class value, you could pass say, a list of boolean functions to check against instead of fixed three, or something else depending on what are you trying to achieve.

On a rust side of things, you can make it more "object oriented" by using traits

trait Executable {
    fn execute(&self);
}

impl Execution {
    fn execute(&self) {
        ...
    }
}
like image 29
Slartibartfast Avatar answered Nov 15 '22 11:11

Slartibartfast


Using default methods on traits is one way (and will probably/hopefully be the idiomatic way in the future; until recently, the struct-with-closures method @Slartibartfast demonstrates was the only thing that actually worked):

#[allow(default_methods)];

trait Executable {
   fn before(&self) -> bool;
   fn during(&self) -> bool;
   fn after(&self) -> bool; 

   fn execute(&self) -> bool {
      self.before() && self.during() && self.after()
   }
}

impl Executable for int {
   fn before(&self) -> bool { *self < 10 }
   fn during(&self) -> bool { *self < 5 }
   fn after(&self) -> bool { *self < 0 }

   // execute is automatically supplied, if it is not implemented here
}

Note that it is possible for an implementation of Executable to override execute at the moment (I've opened an issue about a #[no_override] attribute that would disable this).

Also, default methods are experimental and prone to crashing the compiler (yes, more so than the rest of Rust), but they are improving quickly.

like image 118
huon Avatar answered Nov 15 '22 11:11

huon