Home > OS >  How do I write a function that returns itself?
How do I write a function that returns itself?

Time:11-18

What I want to make is a function, that returns itself, so I can call it like this:

foo()()...()

In C# it would be done via delegates:

delegate SelfFunc SelfFunc();

static void Main() {
    SelfFunc foo = null;
    foo = () => {
        return foo;
    };
    foo()()...();
}

Anticipating questions like "why implement such silly behavior?": I want to sum numbers in a very strange way using single function continues calls: foo(1)(2)(3)() = 6, but in this question I just want to know how to return function itself. Example realization of this method that I made in C#. This is all just for fun and to learn Rust:

static int sum = 0;
delegate dynamic InfFunc(int i = int.MaxValue);
 
static void InfFuncTest() {
    InfFunc f = null;
    f = (int i) => {
        if(i == int.MaxValue) {
            return sum;
        }
        sum  = i;
        return f;
    };
 
    var g = f;
    var value = g(1)(2)(3)();
    Console.WriteLine(value);
}

CodePudding user response:

A function that returns itself is possible on nightly.

First you need to enable the features unboxed_closures and fn_traits.

Then you can define a struct which, when called, returns self. The full code looks something like this:

#![feature(unboxed_closures, fn_traits)]

struct SelfFunc;

impl FnOnce<()>  for SelfFunc {
    type Output = SelfFunc;

    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
        self
    }
}

Then you can call the function as many times as you want:

fn main() {
  let f = SelfFunc;
  f()()()()()();
}

CodePudding user response:

Based on @cameron1024's answer, you can "overload" using traits, but you will need 2 structs to handle the empty case properly of foo() (here called Add) without any arguments returning 0.

#![feature(unboxed_closures, fn_traits)]

struct Add;

impl FnOnce<(u32,)>  for Add {
    type Output = AddImpl;

    extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
        AddImpl(args.0)
    }
}

impl FnOnce<()>  for Add {
    type Output = u32;

    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
        0
    }
}

struct AddImpl(u32);

impl FnOnce<()>  for AddImpl {
    type Output = u32;

    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
        self.0
    }
}

impl FnOnce<(u32,)>  for AddImpl {
    type Output = AddImpl;

    extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
        Self(self.0   args.0)
    }
}


fn main() {
    dbg!( Add(1)(2)(3)() );
    dbg!( Add() );
}

Playground

If you do not care about the no-args foo() requirement, you can make Add a tuple struct instead and remove AddImpl:

#![feature(unboxed_closures, fn_traits)]

struct Add(u32);

impl FnOnce<(u32,)>  for Add {
    type Output = Add;

    extern "rust-call" fn call_once(self, args: (u32,)) -> Self::Output {
        Add(self.0   args.0)
    }
}

impl FnOnce<()>  for Add {
    type Output = u32;

    extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
        self.0
    }
}

fn main() {
    dbg!( Add(1)(2)(3)() );
    //dbg!( Add() ); // doesn't compile
}

Playground

Although I should note that this likely isn't such a great idea, using an slice/iterator would likely result in cleaner code:

fn main() {
    dbg!([1, 2, 3].iter().copied().sum::<u32>());
}

Playground

  • Related