1

I have a collection of different sort functions with a common signature so they can be passed interchangeably to other functions. I want to be able to declare inline that each should match the same signature, so I'll be warned contextually if one of them breaks with it.

Rust has a syntax for declaring function types:

type Foo = Fn(i32) -> i32;

fn bar(func: &Foo) {
    func(12);
}

What I can't figure out is how to declare a regular (non-closure) function that adheres to a function type:

// this works and can be passed as a Foo, but 
// duplicates code and isn't checked against Foo
fn blah(x: i32) -> i32 {
    return x * 2;
}

// this isn't valid syntax
fn blah(x): Foo {
    return x * 2;
}

This is common practice in some other languages that have function types. Is there a syntax I don't know about, is this an upcoming feature, or is there some technical reason preventing it from being added to Rust?

Note; something like this would also serve my purpose, even though it'd be more clunky:

fn blah(x: i32) -> i32 {
    return x * 2;
}: Foo
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
brundolf
  • 1,170
  • 1
  • 9
  • 18
  • I don't don't what would be the use case in Rust, I don't think there is one. Why do you want this ? – Stargateur Jun 19 '19 at 01:09
  • I have a collection of different sort functions with a common signature so they can be passed interchangeably to other functions. I want to be able to declare inline that each should match the same signature, so I'll be warned contextually if one of them breaks with it. – brundolf Jun 19 '19 at 01:52
  • https://play.integer32.com/?version=stable&mode=debug&edition=2018&gist=416c5d037b604d12bcf3b9d2c32a5250 ? There is other way that this one, look like you should learn to code in Rust instead of trying to use other idiom from other language. It could be more easy to help you if you provide more context – Stargateur Jun 19 '19 at 02:15
  • By the way, idiomatic Rust does not use `return` at the end of blocks. – Shepmaster Jun 19 '19 at 02:17
  • @Shepmaster I personally find it more readable in multi-line functions; they wouldn't have included it if it weren't intended to be used. – brundolf Jun 19 '19 at 02:27
  • @Stargateur one of those "some other language"s is Haskell, which is one of Rust's greatest influences. Certain features of it are omitted for practical reasons, but Rust generally tries to include the idioms from Haskell that are feasible to implement. It's completely possible this one wasn't feasible for some reason I'm not seeing, I'm just asking if that's the case. Please only comment if you have something to contribute in the form of answering the original question. – brundolf Jun 19 '19 at 02:30
  • They are intended to be used for early-exit situations, where a keyword is required. You are welcome to do whatever you want, but if you push back against every convention and idiom of a language, that may be a sign that the language is not a good fit for the problem at hand. – Shepmaster Jun 19 '19 at 02:31
  • @Shepmaster It was my understanding that functional idioms are, generally speaking, considered to be welcome in Rust, so it didn't seem unreasonable to ask the original question. As for the explicit return; I was only using it in these single-line functions for clarity. In multi-line functions I do find it more readable, but I wouldn't say that qualifies as "pushing back against every convention and idiom of the language". – brundolf Jun 19 '19 at 02:46
  • 1
    The question itself is reasonable, no argument from me there! – Shepmaster Jun 19 '19 at 02:48
  • 1
    @brundolf a side note really, but, it is most certainly not the _greatest_, but one of the many which had influence on Rust, in the case of Haskell these were typeclasses, and type families: https://doc.rust-lang.org/reference/influences.html – Peter Varo Jun 19 '19 at 08:08

1 Answers1

4

Rust has a syntax for declaring function types:

type Foo = Fn(i32) -> i32;

This is not such a syntax (as you might infer by the fact that it doesn't do what you want). This creates a type alias of the type dyn Fn(i32) -> i32.

You can achieve some of what you want by using a function pointer and creating an unused variable set to the function:

type MyType = fn(i32) -> i32;

fn blah(x: i32) -> i32 {
    x * 2
}

const _IGNORE: MyType = blah;

However, I agree with the comments that you are going about this in a non-idiomatic Rust manner. You want to create an interface that things adhere to, and in Rust that's a trait:

trait Sort {
    fn foo(_: i32) -> i32;
}

struct A;
impl Sort for A {
    fn foo(x: i32) -> i32 {
        x * 2
    }
}

This prevents accidentally "crossing the streams" by providing a fn(String) when you meant an fn(String); the former being "print this string" and the latter being "delete the file named". Function signatures are, at best, a weak interface.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366