I'm writing a worksheet, and want to ask students to write a function that looks like this:
isPrime(int number)
What's that line called - manifest comes to mind, but I don't think that's it...
Could be called header, declaration or signature.
The first one would go well with "function declaration", "function header", "function body".
function prototype,declaration or signature
If you write
bool isPrime(int);
you call this declaration whereas
bool isPrime(int number) { /* code */ }
is the actual definition. (C allows a explicit distinction here)
Generally, your expression is called the (type) signature of a function.
Signature == name, number of parameters, type of parameters, but NOT the return type, whereas declaration == signature + return type
Related
I have the following code in Kotlin:
fun iterate(first: String, second: String, iter: Int, func: (String, String) -> String) {
for(i in 0..iter)
println(func(first, second))
}
fun concatenation(one: String, two: String): String {
return "$one $two";
}
fun main(args: Array<String>) {
iterate("Me", "You", 5, ::concatenation)
iterate("Another", "One", 6) {a, b -> a + b}
}
Can anyone explain what's happening in curly brackets in the second call of iterate function? Am I overriding it?
Also, I tried to swap func and iter paratemers in function declaration. This way I am not able anymore to use curly brackets in the second call and insert a code, because I don't know where to put iter argument.
Your function iterate() takes four parameters: two Strings, and Int, and a function.
When you call iterate(), you can give the String arguments in several ways: for example, you could give the name of a variable holding the String (such as one); or you could give a literal String value (such as "Me").
And you can give the function argument in both of those ways, too.*
The equivalent of the first way is to give a reference to an existing function. That's what ::concatenation is. (:: is used to create function references.)
The equivalent of the second way is to use a lambda, which is a way of writing out the contents of a function. {a, b -> a + b} is a lambda: it's a function which takes two parameters, and returns their concatenation. (In this case the compiler can tell from the context that the two parameters must be Strings; in other cases, you might need to specify their types.)
What's tricky about the code in this question is that the lambda doesn't look like it's being passed as an argument to the function! It's outside the parens:
iterate("Another", "One", 6) {a, b -> a + b}
And this is a feature that's specific to Kotlin: if the last parameter is a function, you can put the lambda after the close paren. (And, if that's the only argument, you can omit the parens entirely.)
So it means exactly the same as:
iterate("Another", "One", 6, {a, b -> a + b})
This may look confusing, but it supports function calls that look like new language syntax. For example, you may have used the with() function:
with (someObject) {
// In here, ‘this’ refers to someObject.
}
That's not a keyword in the language; it's simply a normal function which takes its action as the last parameter.
So I bet you can now see the answer to your last question. If you were to swap the iter and func params around, you'd have to call it like:
iterate("Another", "One", {a, b -> a + b}, 6)
(Because func is no longer the last parameter, it has to be inside the parens now.)
(* There are additional ways to specify string params and function params, too, but there's no room to go into them all here!)
Your func parameter's type is a function - its type is (String, String) -> String which means it takes two String parameters (in the parentheses) and returns a String (after the arrow).
That's what all function types look like, (x) -> y. A function type that takes no parameters and doesn't return a value has a type () -> Unit (because every function returns something in Kotlin, Unit is the "no meaningful value" type).
So for your func parameter, you can pass in any function with that type - takes two strings, returns a string. Your concatenation function matches that, so you can pass it in - you're using a function reference, ::concatenation which is a way to pass that function - it's a reference to it.
With your second iterate call, you're creating a function object to pass in, instead of referring to one that's declared as an actual method on the class. You're using a lambda that takes two parameters, a and b, and calls + on them (and implicitly returns that value as the result).
Now you're not saying that they're Strings here (you could declare their types explicitly if you wanted), but the type system is basically checking that this can apply to two String variables, and that the result of + on those would also be a String. So it all works fine, and it can be used in your iterate function.
Like #IR42 says in the comments, you're using a trailing lambda - basically when the last parameter in a function call is a lambda, instead of keeping it in the parentheses, you can move it outside (and remove the parentheses if the lambda was the only thing in there).
But this only works when it's the last parameter - otherwise it wouldn't know for sure which one you'd moved out! - which is why you can't change the order and keep the trailing lambda. You can switch up the order, but the call will have to be like this:
iterate("Me", "You", ::concatenation, 5)
iterate("Another", "One", {a, b -> a + b}, 6)
I'd like to create a function which accepts a function that accepts specific types of parameters as an argument. For example:
myFn(Function paramFn) {
paramFn([1, 2, 3]);
}
How can I ensure that paramFn accepts a List<int> as an only parameter?
You can use typedef to define the signature you want like described in Kul's answer or you can simply inline the function signature in the parameter:
myFn(void paramFn(List<int> l)) {
paramFn([1, 2, 3]);
}
You can use typedef to associate a symbol with a function that satisfies the signature you want. Something like
typedef void ParamFn(List<int> l);
myFn(ParamFn f) {
f('abc'); // compile time error
f([1,2,3]); // works fine
}
That's what typedefs are for, although I'm not sure how rigid the strong mode will enforce it yet.
I am reading about boost::function and I am a bit confused about its use and its relation to other C++ constructs or terms I have found in the documentation, e.g. here.
In the context of C++ (C++11), what is the difference between an instance of boost::function, a function object, a functor, and a lambda expression? When should one use which construct? For example, when should I wrap a function object in a boost::function instead of using the object directly?
Are all the above C++ constructs different ways to implement what in functional languages is called a closure (a function, possibly containing captured variables, that can be passed around as a value and invoked by other functions)?
A function object and a functor are the same thing; an object that implements the function call operator operator(). A lambda expression produces a function object. Objects with the type of some specialization of boost::function/std::function are also function objects.
Lambda are special in that lambda expressions have an anonymous and unique type, and are a convenient way to create a functor inline.
boost::function/std::function is special in that it turns any callable entity into a functor with a type that depends only on the signature of the callable entity. For example, lambda expressions each have a unique type, so it's difficult to pass them around non-generic code. If you create an std::function from a lambda then you can easily pass around the wrapped lambda.
Both boost::function and the standard version std::function are wrappers provided by the library. They're potentially expensive and pretty heavy, and you should only use them if you actually need a collection of heterogeneous, callable entities. As long as you only need one callable entity at a time, you are much better off using auto or templates.
Here's an example:
std::vector<std::function<int(int, int)>> v;
v.push_back(some_free_function); // free function
v.push_back(&Foo::mem_fun, &x, _1, _2); // member function bound to an object
v.push_back([&](int a, int b) -> int { return a + m[b]; }); // closure
int res = 0;
for (auto & f : v) { res += f(1, 2); }
Here's a counter-example:
template <typename F>
int apply(F && f)
{
return std::forward<F>(f)(1, 2);
}
In this case, it would have been entirely gratuitous to declare apply like this:
int apply(std::function<int(int,int)>) // wasteful
The conversion is unnecessary, and the templated version can match the actual (often unknowable) type, for example of the bind expression or the lambda expression.
Function Objects and Functors are often described in terms of a
concept. That means they describe a set of requirements of a type. A
lot of things in respect to Functors changed in C++11 and the new
concept is called Callable. An object o of callable type is an
object where (essentially) the expression o(ARGS) is true. Examples
for Callable are
int f() {return 23;}
struct FO {
int operator()() const {return 23;}
};
Often some requirements on the return type of the Callable are added
too. You use a Callable like this:
template<typename Callable>
int call(Callable c) {
return c();
}
call(&f);
call(FO());
Constructs like above require you to know the exact type at
compile-time. This is not always possible and this is where
std::function comes in.
std::function is such a Callable, but it allows you to erase the
actual type you are calling (e.g. your function accepting a callable
is not a template anymore). Still calling a function requires you to
know its arguments and return type, thus those have to be specified as
template arguments to std::function.
You would use it like this:
int call(std::function<int()> c) {
return c();
}
call(&f);
call(FO());
You need to remember that using std::function can have an impact on
performance and you should only use it, when you are sure you need
it. In almost all other cases a template solves your problem.
What does "Overloaded"/"Overload" mean in regards to programming?
It means that you are providing a function (method or operator) with the same name, but with a different signature.
For example:
void doSomething();
int doSomething(string x);
int doSomething(int a, int b, int c);
Basic Concept
Overloading, or "method overloading" is the name of the concept of having more than one methods with the same name but with different parameters.
For e.g. System.DateTime class in c# have more than one ToString method. The standard ToString uses the default culture of the system to convert the datetime to string:
new DateTime(2008, 11, 14).ToString(); // returns "14/11/2008" in America
while another overload of the same method allows the user to customize the format:
new DateTime(2008, 11, 14).ToString("dd MMM yyyy"); // returns "11 Nov 2008"
Sometimes parameter name may be the same but the parameter types may differ:
Convert.ToInt32(123m);
converts a decimal to int while
Convert.ToInt32("123");
converts a string to int.
Overload Resolution
For finding the best overload to call, compiler performs an operation named "overload resolution". For the first example, compiler can find the best method simply by matching the argument count. For the second example, compiler automatically calls the decimal version of replace method if you pass a decimal parameter and calls string version if you pass a string parameter. From the list of possible outputs, if compiler cannot find a suitable one to call, you will get a compiler error like "The best overload does not match the parameters...".
You can find lots of information on how different compilers perform overload resolution.
A function is overloaded when it has more than one signature. This means that you can call it with different argument types. For instance, you may have a function for printing a variable on screen, and you can define it for different argument types:
void print(int i);
void print(char i);
void print(UserDefinedType t);
In this case, the function print() would have three overloads.
It means having different versions of the same function which take different types of parameters. Such a function is "overloaded". For example, take the following function:
void Print(std::string str) {
std::cout << str << endl;
}
You can use this function to print a string to the screen. However, this function cannot be used when you want to print an integer, you can then make a second version of the function, like this:
void Print(int i) {
std::cout << i << endl;
}
Now the function is overloaded, and which version of the function will be called depends on the parameters you give it.
Others have answered what an overload is. When you are starting out it gets confused with override/overriding.
As opposed to overloading, overriding is defining a method with the same signature in the subclass (or child class), which overrides the parent classes implementation. Some language require explicit directive, such as virtual member function in C++ or override in Delphi and C#.
using System;
public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}
public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}
An overloaded method is one with several options for the number and type of parameters. For instance:
foo(foo)
foo(foo, bar)
both would do relatively the same thing but one has a second parameter for more options
Also you can have the same method take different types
int Convert(int i)
int Convert(double i)
int Convert(float i)
Just like in common usage, it refers to something (in this case, a method name), doing more than one job.
Overloading is the poor man's version of multimethods from CLOS and other languages. It's the confusing one.
Overriding is the usual OO one. It goes with inheritance, we call it redefinition too (e.g. in https://stackoverflow.com/users/3827/eed3si9n's answer Line provides a specialized definition of Draw().
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.