Why the strong difference between closures and functions in Rust and how to work around it? - function

I just ran into a problem with how Rust handles closures.
Let's assume I'm a library author and have written this method
fn get(&mut self, handler: fn() -> &str){
//do something with handler
}
Now if a user wants to call this method like this
let foo = "str";
server.get(|| -> &str { foo });
It won't work because Rust, according to it's documentation makes a strong difference between regular functions and closures.
Do I as a library author always have to make such methods accept closures instead of regular functions to not restrict library users too much?
Also it seems to me as if closures are the only way to write anonymous functions or am I mistaken?

Currently, fn() types can be automatically "promoted" to || types. (A closure with an empty environment, I suppose.) For example, this works:
fn get(handler: || -> &str) -> &str {
handler()
}
fn main() {
fn handler_fn() -> &str { "handler_fn" }
let handler_cl = || -> &str "handler_cl";
println!("{}", get(handler_fn));
println!("{}", get(handler_cl));
}
So if your library function get doesn't care whether handler is a closure or not, then it seems reasonable to just accept closures for maximum flexibility. But this isn't always possible. For example, if you wanted to execute handler in another task, then I believe it must be a fn or a proc type. (I'm not 100% certain here---I may be missing a detail.)
With regard to anonymous functions, yes, a || or a proc closure are the only two ways to write anonymous functions.

Related

Use function also as method and implement it only once

I am writting a library in which I will need to provide a lot of functions or methods to provide operations. For example, one of the operations is to compute the cosine on a given value. So I would write something like this:
fn cos<T>(value: &MyValue<T>) -> MyValue<T> {
todo!()
}
Then, I can just call it like let result = cos(&my_value).
Is there a way, or best practice so that I could also offer an API like let result = my_value.cos() without having to write the the cos function twice? I've been thinking about creating my own macro to do it, but I was wondering if there's another library providing this feature or if there's just a better way to do this.
You can do this by calling the function within the method implementation like so:
fn cos<T>(val: &MyValue<T>) -> MyValue<T> {
// snip
}
struct MyValue<T> {
// snip
}
impl<T> MyValue<T> {
fn cos(&self) -> Self {
cos(self)
}
}
That being said, I'm not sure exactly why you would want to - as others have pointed out the standard library only provides methods in situations such as this. This could be seen as a violation of the principle of least astonishment.

Lambdas assigned to variables in Kotlin. Why?

I noticed that I get the same effect if I define this trivial function:
fun double ( i: Int ) = i*2
and if I define a variable and assign a lambda (with an identical body) to it:
var double = { i : Int -> i*2 }
I get the same result if I call double(a) with either declaration.
This leaves me confused. When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?
When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?
Whenever you have the choice of either, you should use a fun declaration. Even with a fun you can still get a first-class callable object from it by using a function reference.
On the JVM, a fun is significantly more lightweight, both in terms of RAM and invocation overhead. It compiles into a Java method, whereas a val compiles into an instance field + getter + a synthetic class that implements a functional interface + a singleton instance of that class that you must fetch, dereference, and invoke a method on it.
You should consider a function-typed val or var only when something is forcing you to do it. One example is that you can dynamically replace a var and effectively change the definition of the function. You may also receive function objects from the outside, or you may need to comply with an API that needs them.
In any case, if you ever use a function-typed property of a class, you'll know why you're doing it.
First, if I understand you right, your question is "Why are functions first-class citizens in Kotlin -- And when to use them as such?", right?
Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. You can operate with functions in any way that is possible for other non-function values. (see here)
As stated in the docs, one use case are higher-order functions. As a first step, I will leave the wikipedia link here: https://en.wikipedia.org/wiki/Higher-order_function
Basically, a higher-order function is a function that takes functions as parameters, or returns a function.
This means that a higher-order function has at least one parameter of a function type or returns a value of a function type.
Following a short example of a higher-order function that receives a parameter of function type (Int) -> Boolean:
fun foo(pred: (Int) -> Boolean) : String = if(pred(x)) "SUCCESS" else "FAIL"
This higher-order function can now be called with any (Int) -> Boolean function.
The docs also state ... [can be used] in any way that is possible for other non-function values.
This means that you can, for example, assign different functions to a variable, depending on your current context.
For example:
// This example is verbose on purpose ;)
var checker: (Int) -> Boolean
if (POSITIVE_CHECK) {
checker = { x -> x > 0 } // Either store this function ...
} else {
checker = { x -> x < 0 } // ... or this one ...
}
if (checker(someNumber)) { // ... and use whatever function is now stored in variable "checker" here
print("Check was fine")
}
(Code untested)
You can define variable and assign it lambda when you want change behaviour for some reason. For example, you have different formula for several cases.
val formula: (Int) -> Int = when(value) {
CONDITION1 -> { it*2 }
CONDITION2 -> { it*3 }
else -> { it }
}
val x: Int = TODO()
val result = formula(x)
If you simply need helper function, you should define it as fun.
If you pass a lambda as a parameter of a function it will be stored in a variable. The calling application might need to save that (e.g. event listener for later use). Therefore you need to be able to store it as a variable as well. As said in the answer however, you should do this only when needed!
For me, I would write the Lambda variable as followed:
var double: (Int) -> Int = { i -> //no need to specify parameter name in () but in {}
i*2
}
So that you can easily know that its type is (i: Int) -> Int, read as takes an integer and returns an integer.
Then you can pass it to somewhere say a function like:
fun doSomething(double: (Int) -> Int) {
double(i)
}

Missing implementation for top level functions

I am trying to make a trait usable on top-level functions in Rust.
trait FnTrait {
fn call(self);
}
impl FnTrait for fn() {
fn call(self) {
self()
}
}
fn foo() {
println!("Hello, World!")
}
fn main() {
FnTrait::call(foo)
}
However the code below fails to compile with (Playground Link)
error[E0277]: the trait bound `fn() {foo}: FnTrait` is not satisfied
--> <anon>:16:5
|
16 | FnTrait::call(foo)
| ^^^^^^^^^^^^^ the trait `FnTrait` is not implemented for `fn() {foo}`
|
= help: the following implementations were found:
<fn() as FnTrait>
= note: required by `FnTrait::call`
I found I can trick it into compiling by casting foo like so
FnTrait::call(foo as fn())
But it is annoying and some of the functions in my program are more complicated than foo. Any way to avoid the cast? Is my trait wrong somehow?
Every function in Rust has its own type. As you can see, foo isn't a fn(), it's a fn() {foo}; sadly, this is not an actual type you can write in source, that's just a compiler message thing. The distinction exists to make it easier for the compiler to let you pass around functions as values whilst still being able to inline the calls.
The consequence is that named functions pointers cannot be turned into general function pointers without either a cast or a type hint. For example, this works:
fn foo() {
println!("Hello, World!")
}
fn bar(f: fn()) {
f()
}
fn main() {
bar(foo)
}
However, I'm not aware of any way to leverage this to get the trait to work.
The only way forward is to stop trying to implement the trait for function pointers, and instead implement it for everything callable:
trait FnTrait {
fn call(self);
}
impl<F> FnTrait for F where F: FnOnce() {
fn call(self) {
self()
}
}
fn foo() {
println!("Hello, World!")
}
fn main() {
foo.call();
}
(Semi-relevant answer about the difference between Fn, FnMut and FnOnce.)
This will work for anything that's callable with that signature, including both functions and closures. The downside is that you can only have one such implementation. You can't implement this trait for any other signature.
One generic implementation, or many specific implementations and lots of manual casting. Pick your poison.
As an aside: there's no such thing as a "top level function" in Rust, at least not as a thing distinct from other kinds of functions. Functions are functions, no matter where they appear. Instance functions a.k.a. methods are still regular functions, it's just that their first argument is called "self".

What is the benefit of nesting functions (in general/in Swift)

I'm just learning some Swift and I've come across the section that talks about nesting functions:
Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.
From here
So if the purported benefit is to "organize the code", why not just have the nested function independently, outside of the outer function? That, to me, seems more organized.
The only benefit I can discern is that you "have access to variables that were declared in the outer function", but this seems trivial in comparison to the messiness of having nested functions.
Any thoughts?
So if the purported benefit is to "organize the code", why not just have the nested function independently, outside of the outer function? That, to me, seems more organized.
Oh, I totally disagree. If the only place where the second function is needed is inside the first function, keeping it inside the first function is much more organized.
Real-life examples here: http://www.apeth.com/swiftBook/ch02.html#_function_in_function
Plus, a function in a function has the local environment in scope. Code inside the nested function can "see" local variables declared before the nested function declaration. This can be much more convenient and natural than passing a bunch of parameters.
However, the key thing that a local function lets you do that you could not readily do in any other way is that you can form the function in real time (because a function is a closure) and return it from the outer function.
http://www.apeth.com/swiftBook/ch02.html#_function_returning_function
One really nice thing is that Xcode will indent nested functions within their parent function in the function pop-up. The function popup is much easier to navigate with functions related to recalculating the layout indented and all grouped in one place.
IMO, the only difference of closures and nested functions is recursion. You can refer the function itself in the function body without a trick.
func a() {
func b() {
b() // Infinite loop!
}
b()
}
Captured reference type object dies when the capturer dies. In this case, capturer is the function's lexical scope. Which means the function is going to die when it finishes its execution.
Technically, this makes a reference-cycle, and usually discouraged. But this can be useful if you use this wisely.
For example, combine this with asynchronous operations.
func spawnAsyncOp1(_ completion: #escaping () -> Void) {
enum Continuation {
case start
case waitForSomethingElse1
case retry
case end
}
let someResource = SomeResource()
func step(_ c: Continuation) {
switch c {
case .start:
return step(.waitForSomethingElse1)
case .waitForSomethingElse1:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10), execute: {
let fc = (someResource.makeRandomResult() % 100 < 50) ? .end : .retry as Continuation
print("\(fc)")
return step(fc)
})
case .retry:
return step(.start)
case .end:
return completion()
}
}
return step(.start)
}
It can make resource management in a coroutine execution simpler without an explicit object instance. Resources are simply captured in function spawnAsyncOp1 and will be released when the function dies.

How do you return non-copyable types?

I am trying to understand how you return non-primitives (i.e. types that do not implement Copy). If you return something like a i32, then the function creates a new value in memory with a copy of the return value, so it can be used outside the scope of the function. But if you return a type that doesn't implement Copy, it does not do this, and you get ownership errors.
I have tried using Box to create values on the heap so that the caller can take ownership of the return value, but this doesn't seem to work either.
Perhaps I am approaching this in the wrong manner by using the same coding style that I use in C# or other languages, where functions return values, rather than passing in an object reference as a parameter and mutating it, so that you can easily indicate ownership in Rust.
The following code examples fails compilation. I believe the issue is only within the iterator closure, but I have included the entire function just in case I am not seeing something.
pub fn get_files(path: &Path) -> Vec<&Path> {
let contents = fs::walk_dir(path);
match contents {
Ok(c) => c.filter_map(|i| { match i {
Ok(d) => {
let val = d.path();
let p = val.as_path();
Some(p)
},
Err(_) => None } })
.collect(),
Err(e) => panic!("An error occurred getting files from {:?}: {}", pa
th, e)
}
}
The compiler gives the following error (I have removed all the line numbers and extraneous text):
error: `val` does not live long enough
let p = val.as_path();
^~~
in expansion of closure expansion
expansion site
reference must be valid for the anonymous lifetime #1 defined on the block...
...but borrowed value is only valid for the block suffix following statement
let val = d.path();
let p = val.as_path();
Some(p)
},
You return a value by... well returning it. However, your signature shows that you are trying to return a reference to a value. You can't do that when the object will be dropped at the end of the block because the reference would become invalid.
In your case, I'd probably write something like
#![feature(fs_walk)]
use std::fs;
use std::path::{Path, PathBuf};
fn get_files(path: &Path) -> Vec<PathBuf> {
let contents = fs::walk_dir(path).unwrap();
contents.filter_map(|i| {
i.ok().map(|p| p.path())
}).collect()
}
fn main() {
for f in get_files(Path::new("/etc")) {
println!("{:?}", f);
}
}
The main thing is that the function returns a Vec<PathBuf> — a collection of a type that owns the path, and are more than just references into someone else's memory.
In your code, you do let p = val.as_path(). Here, val is a PathBuf. Then you call as_path, which is defined as: fn as_path(&self) -> &Path. This means that given a reference to a PathBuf, you can get a reference to a Path that will live as long as the PathBuf will. However, you are trying to keep that reference around longer than vec will exist, as it will be dropped at the end of the iteration.
How do you return non-copyable types?
By value.
fn make() -> String { "Hello, World!".into() }
There is a disconnect between:
the language semantics
the implementation details
Semantically, returning by value is moving the object, not copying it. In Rust, any object is movable and, optionally, may also be Clonable (implement Clone) and Copyable (implement Clone and Copy).
That the implementation of copying or moving uses a memcpy under the hood is a detail that does not affect the semantics, only performance. Furthermore, this being an implementation detail means that it can be optimized away without affecting the semantics, which the optimizer will try very hard to do.
As for your particular code, you have a lifetime issue. You cannot return a reference to a value if said reference may outlive the value (for then, what would it reference?).
The simple fix is to return the value itself: Vec<PathBuf>. As mentioned, it will move the paths, not copy them.