Rust scoping rules for struct-owned functions - function

I am trying to understand what exactly the scope is for functions defined within an impl block but which don't accept &self as a parameter. For example, why doesn't the following chunk of code compile? I get the error "cannot find function generate_a_result in this scope".
pub struct Blob {
num: u32,
}
impl Blob {
pub fn new() -> Blob {
generate_a_result()
}
fn generate_a_result() -> Blob {
let result = Blob {
num: 0
};
result
}
}

These functions are called associated functions. And they live in the namespace of the type. They always have to be called like Type::function(). In your case, that's Blob::generate_a_result(). But for referring to your own type, there is the special keyword Self. So the best solution is:
Self::generate_a_result()

Related

How to return concrete type from generic function?

In the example below the Default trait is used just for demonstration purposes.
My questions are:
What is the difference between the declarations of f() and g()?
Why g() doesn't compile since it's identical to f()?
How can I return a concrete type out of a impl trait generically typed declaration?
struct Something {
}
impl Default for Something {
fn default() -> Self {
Something{}
}
}
// This compiles.
pub fn f() -> impl Default {
Something{}
}
// This doesn't.
pub fn g<T: Default>() -> T {
Something{}
}
What is the difference between the declarations of f() and g()?
f returns some type which implements Default. The caller of f has no say in what type it will return.
g returns some type which implements Default. The caller of g gets to pick the exact type that must be returned.
You can clearly see this difference in how f and g can be called. For example:
fn main() {
let t = f(); // this is the only way to call f()
let t = g::<i32>(); // I can call g() like this
let t = g::<String>(); // or like this
let t = g::<Vec<Box<u8>>(); // or like this... and so on!
// there's potentially infinitely many ways I can call g()
// and yet there is only 1 way I can call f()
}
Why g() doesn't compile since it's identical to f()?
They're not identical. The implementation for f compiles because it can only be called in 1 way and it will always return the exact same type. The implementation for g fails to compile because it can get called infinitely many ways for all different types but it will always return Something which is broken.
How can I return a concrete type out of a impl trait generically typed declaration?
If I'm understanding your question correctly, you can't. When you use generics you let the caller decide the types your function must use, so your function's implementation itself must be generic. If you want to construct and return a generic type within a generic function the usual way to go about that is to put a Default trait bound on the generic type and use that within your implementation:
// now works!
fn g<T: Default>() -> T {
T::default()
}
If you need to conditionally select the concrete type within the function then the only other solution is to return a trait object:
struct Something;
struct SomethingElse;
trait Trait {}
impl Trait for Something {}
impl Trait for SomethingElse {}
fn g(some_condition: bool) -> Box<dyn Trait> {
if some_condition {
Box::new(Something)
} else {
Box::new(SomethingElse)
}
}
how can I return a concrete type out of a "impl trait" generically typed declaration?
By "impl trait" generically typed declaration I presume you mean "impl trait" rewritten to use named generics. However, that's a false premise - impl Trait in return position was introduced precisely because you can't express it using named generics. To see this, consider first impl Trait in argument position, such as this function:
fn foo(iter: impl Iterator<Item = u32>) -> usize {
iter.count()
}
You can rewrite that function to use named generics as follows:
fn foo<I: Iterator<Item = u32>>(iter: I) -> usize {
iter.count()
}
Barring minor technical differences, the two are equivalent. However, if impl Trait is in return position, such as here:
fn foo() -> impl Iterator<Item = u32> {
vec![1, 2, 3].into_iter()
}
...you cannot rewrite it to use generics without losing generality. For example, this won't compile:
fn foo<T: Iterator<Item = u32>>() -> T {
vec![1, 2, 3].into_iter()
}
...because, as explained by pretzelhammer, the signature promises the caller the ability to choose which type to return (out of those that implement Iterator<Item = u32>), but the implementation only ever returns a concrete type, <Vec<u32> as IntoIterator>::IntoIter.
On the other hand, this does compile:
fn foo() -> <Vec<u32> as IntoIterator>::IntoIter {
vec![1, 2, 3].into_iter()
}
...but now the generality is lost because foo() must be implemented as a combination of Vec and into_iter() - even adding a map() in between the two would break it.
This also compiles:
fn foo() -> Box<dyn Iterator<Item = u32>> {
Box::new(vec![1, 2, 3].into_iter())
}
...but at the cost of allocating the iterator on the heap and disabling some optimizations.

How to write a function that takes a slice of functions?

I am trying to write a function that takes a slice of functions. Consider the following simple illustration:
fn g<P: Fn(&str) -> usize>(ps: &[P]) { }
fn f1() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn f2() -> impl Fn(&str) -> usize { |s: &str| s.len() }
fn main() {
g(&[f1(), f2()][..]);
}
It fails to compile:
error[E0308]: mismatched types
--> src/main.rs:6:15
|
6 | g(&[f1(), f2()][..]);
| ^^^^ expected opaque type, found a different opaque type
|
= note: expected type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
found type `impl for<'r> std::ops::Fn<(&'r str,)>` (opaque type)
Is there any way to do this?
Your problem is that every element of the array must be of the same type, but the return of a function declared as returning impl Trait is an opaque type, that is an unspecified, unnamed type, that you can only use by means of the given trait.
You have two functions that return the same impl Trait but that does not mean that they return the same type. In fact, as your compiler shows, they are different opaque types, so they cannot be part of the same array. If you were to write an array of values of the same type, such as:
g(&[f1(), f1(), f1()]);
then it would work. But with different functions, there will be different types and the array is impossible to build.
Does that mean there is no solution for your problem? Of course not! You just have to invoke dynamic dispatch. That is you have to make your slice of type &[&dyn Fn(&str) -> usize]. For that you need to do two things:
Add a level of indirection: dynamic dispatching is always done via references or pointers (&dyn Trait or Box<dyn Trait> instead of Trait).
Do an explicit cast to the &dyn Trait to avoid ambiguities in the conversion.
There are many ways to do the cast: you can cast the first element of the array, or you can declare the temporary variables, or give the slice a type. I prefer the latter, because it is more symmetric. Something like this:
fn main() {
let fns: &[&dyn Fn(&str) -> usize] =
&[&f1(), &f2()];
g(fns);
}
Link to a playground with this solution.

How to use an external object in a struct callback such as when appending data to a CSV?

My understanding was that objects created outside of the scope are available inside the scope (hence things such as shadowing allowed), but it does not seem to work in this scenario:
extern crate csv;
extern crate rand;
use rand::Rng;
use std::path::Path;
use std::time::SystemTime;
#[derive(Debug)]
struct Event {
time: SystemTime,
value: u32,
}
impl Event {
fn new(t: SystemTime, n: u32) -> Event {
Event {
time: SystemTime,
value: n,
}
}
}
struct Process;
impl Process {
fn new() -> Process {
Process {}
}
fn start(&self) {
loop {
let now = SystemTime::now();
let random_number: u32 = rand::thread_rng().gen();
let event = Event::new(now, random_number);
self.callback(event);
}
}
fn callback(&self, event: Event) {
println!("{:?}", event);
wtr.write_record(&event).unwrap();
wtr.flush().unwrap();
}
}
fn main() {
let file_path = Path::new("test.csv");
let mut wtr = csv::Writer::from_path(file_path).unwrap();
let process: Process = Process::new();
process.start();
}
The errors are:
error[E0423]: expected value, found struct `SystemTime`
--> src/main.rs:17:19
|
17 | time: SystemTime,
| ^^^^^^^^^^ constructor is not visible here due to private fields
error[E0425]: cannot find value `wtr` in this scope
--> src/main.rs:41:9
|
41 | wtr.write_record(&event).unwrap();
| ^^^ not found in this scope
error[E0425]: cannot find value `wtr` in this scope
--> src/main.rs:42:9
|
42 | wtr.flush().unwrap();
| ^^^ not found in this scope
How can I append data (Event) to a CSV file from inside the callback function for Process?
I strongly encourage you to go back and re-read The Rust Programming Language, specifically the chapter about functions. This code appears to show fundamental issues around the entire model of how functions work.
For example, the code attempts to make use of the variable wtr in the function callback without it being passed in either directly or indirectly.
If such code worked1, programmers would likely hate dealing with this language because it would be almost impossible to tell what and where the value wtr even came from.
The solution is straightforward: pass any value that a piece of code needs to that code. Then it's easy (or easier) to tell where the value came from. There are multiple avenues that can work.
Pass an argument to the callback method:
use std::io::Write;
impl Process {
fn start<R>(&self, wtr: &mut csv::Writer<R>)
where
R: Write,
{
loop {
// ...
self.callback(wtr, event);
}
}
fn callback<R>(&self, wtr: &mut csv::Writer<R>, event: Event)
where
R: Write,
{
// ...
}
}
fn main() {
// ...
process.start(&mut wtr);
}
Pass an argument to the constructor and save it inside the struct:
use std::io::Write;
struct Process<'a, R>
where
R: Write + 'a,
{
wtr: &'a mut csv::Writer<R>,
}
impl<'a, R> Process<'a, R>
where
R: Write,
{
fn new(wtr: &'a mut csv::Writer<R>) -> Self {
Process { wtr }
}
// ...
fn callback(&self, event: Event) {
// ...
self.wtr.write_record(event).unwrap();
self.wtr.flush().unwrap();
}
}
fn main() {
// ...
let process = Process::new(&mut wtr);
}
The code has other issues in how it uses the CSV library that I'm ignoring because they are unrelated to your question. I encourage you to start with a simpler piece of code, get it working, then make it more complex. That way you are only dealing with simpler errors at first.
Once you understand this basic usage of functions, you may wish to learn about closures. These allow you to "capture" variables from an outer scope and pass them in (in the same two methods as above) without having to deal with the specific count or type of variables.
objects created outside of the scope are available inside the scope
This is true for a single function. It does not apply across functions.
hence things such as shadowing allowed
Shadowing has nothing to to with scopes. You are allowed to shadow inside the same scope:
let a = Some(32);
let a = a.unwrap();
1. Such languages exist; they are languages with dynamic scope and some people prefer them. They are in the minority, programs written in these languages are hard to reason about!

Rust Json serialization overlapping responsibilities

I'm learning Json serialization in Rust, in particular, how to serialize Rust objects to Json.
Currently I see 3 methods of converting an instance of a struct to Json:
Deriving Encodable trait
Manual implementation of ToJson trait
Manual implementation of Encodable trait
Below code illustrates all 3 approaches:
extern crate serialize;
use serialize::{Encoder, Encodable, json};
use serialize::json::{Json, ToJson};
use std::collections::TreeMap;
fn main() {
let document = Document::new();
let word_document = WordDocument::new();
println!("1. Deriving `Encodable`: {}", json::encode(&document));
println!("2. Manually implementing `ToJson` trait: {}", document.to_json());
println!("3. Manually implementing `Encodable` trait: {}", json::encode(&word_document));
}
#[deriving(Encodable)]
struct Document<'a> {
metadata: Vec<(&'a str, &'a str)>
}
impl<'a> Document<'a> {
fn new() -> Document<'a> {
let metadata = vec!(("Title", "Untitled Document 1"));
Document {metadata: metadata}
}
}
impl<'a> ToJson for Document<'a> {
fn to_json(&self) -> Json {
let mut tm = TreeMap::new();
for &(ref mk, ref mv) in self.metadata.iter() {
tm.insert(mk.to_string(), mv.to_string().to_json());
}
json::Object(tm)
}
}
struct WordDocument<'a> {
metadata: Vec<(&'a str, &'a str)>
}
impl<'a> WordDocument<'a> {
fn new() -> WordDocument<'a> {
let metadata = vec!(("Title", "Untitled Word Document 1"));
WordDocument {metadata: metadata}
}
}
impl<'a, E, S: Encoder<E>> Encodable<S, E> for WordDocument<'a> {
fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_map(self.metadata.len(), |e| {
let mut i = 0;
for &(ref key, ref val) in self.metadata.iter() {
try!(e.emit_map_elt_key(i, |e| key.encode(e)));
try!(e.emit_map_elt_val(i, |e| val.encode(e)));
i += 1;
}
Ok(())
})
}
}
Rust playpen: http://is.gd/r7cYmE
Results:
1. Deriving `Encodable`: {"metadata":[["Title","Untitled Document 1"]]}
2. Manually implementing `ToJson` trait: {"Title":"Untitled Document 1"}
3. Manually implementing `Encodable` trait: {"Title":"Untitled Word Document 1"}
First method is fully automatic, but does not provide sufficient flexibility.
Second and third achieve same level of flexibility by specifying the serialization process manually. In my case I want document metadata to be serialized as an object, not as an array (which is what deriving implementation gives me).
Questions:
Why do methods 2 and 3 exist at all? I don't understand the reason for the overlap between them. I would expect there to exist only one automatic (deriving) method of serialization and one manual.
If I want manual serialization, which method should I choose and why?
Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents?
Why does rust stdlib use method 3 even for primitives, while not using method 2 internally?
Why do methods 2 and 3 exist at all? I don't understand the reason for the overlap between them. I would expect there to exist only one automatic (deriving) method of serialization and one manual.
Method 2 (the ToJson trait) is specific to encoding JSON. It returns JSON objects, instead of writing to a stream. One example of use is for mapping to custom representations - see this example in the documentation.
Method 3 (implementing Encodable) has to exist for method 1 to work.
Am I right in assuming that method 2 will build a Json enum in memory (besides the struct itself) and is a worse fit for huge documents (multi megabytes), while method 3 is streaming and safer for huge documents?
Yes. ToJson creates a nested Json enum of the whole object, while Encodable streams to a Writer.
If I want manual serialization, which method should I choose and why?
Why does rust stdlib use method 3 even for primitives, while not using method 2 internally?
You should use Encodable. It is not specific to the JSON format, does not use an intermediate representation (so can be streamed instead of stored in memory) and should continue to work with new formats added to the library.

What are the differences between functions and methods in Swift?

I always thought functions and methods were the same, until I was learning Swift through the "Swift Programming Language" eBook. I found out that I cannot use greet("John", "Tuesday") to call a function that I declared inside a class, as shown in the eBook in the screen shot below:
I received a error saying that "Missing argument label 'day:' in call" as per this screen shot:
Here is the code:-
import Foundation
import UIKit
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//var dailyStatement = greet("John", "Tuesday")
var dailyStatement = greet("John", day: "Tuesday")
println(dailyStatement)
}
func greet(name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
}
After some research, I found this post: Difference between a method and a function, and it seems to me that the function that I declared inside a class is actually called a method. So, the syntax that I use to call the method is different compared to the syntax that I use to call a function.
I never realized this difference when I was programming in Objective-C.
What are the differences between functions and methods in Swift?
When do we use functions and when do we use methods in Swift?
After a few hours of reading and experimenting, here are the things that I found out:-
Functions in Swift
Functions are self-contained chunks of code that perform a specific
task. You give a function a name that identifies what it does, and
this name is used to “call” the function to perform its task when
needed.
Resource: Official Apple Documentation on Functions in Swift
Function Parameter Names
However, these parameter names are only used within the body of the
function itself, and cannot be used when calling the function. These
kinds of parameter names are known as local parameter names, because
they are only available for use within the function’s body.
It means that by default, all the parameters for Function are local parameters.
But, sometimes we want to indicate the purpose of each parameter. So, we can actually define an external parameter name for each parameter. Example Code:
func someFunction(externalParameterName localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
Another way to make the external parameter name is using hash symbol (#) to shorten the name.
func someFunction(#localParameterName: Int) {
// function body goes here, and can use localParameterName
// to refer to the argument value for that parameter
}
To call the above functions with external parameter, you may use
someFunction(localParameterName:10)
Methods in Swift
Methods are functions that are associated with a particular type.
Classes, structures, and enumerations can all define instance methods,
which encapsulate specific tasks and functionality for working with an
instance of a given type.
Resource: Official Apple Documentation on Methods in Swift
However, the default behavior of local names and external names is
different for functions and methods.
Specifically, Swift gives the first parameter name in a method a local
parameter name by default, and gives the second and subsequent
parameter names both local and external parameter names by default.
Code below shows the differences for default and non-default parameters for method in Swift.
import Foundation
import UIKit
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Default methods calling
var dailyStatement = greet("Rick", day: "Tuesday")
println(dailyStatement)
//First parameter is also an external parameter
var dailyStatement2 = greet2(name:"John", day: "Sunday")
println(dailyStatement2)
}
//Default: First Parameter is the local parameter, the rest are external parameters
func greet (name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
//Use Hash symbol to make the First parameter as external parameter
func greet2 (#name: String, day: String) -> String {
return "Hello \(name), today is \(day)."
}
}
I might miss some important details. Hope someone can provide a better answer.
As you said yourself, methods are functions, but in a class. In objective-c you never realized this, because we were only coding in classes. Every function that we wrote was a method of a class (ViewController or some other class we created).
In Swift we have the ability to create functions that are not inside some class. The main reason for doing this is to write functions that are not tied to any class, and can be used wherever we need them. So if you have a function that is related to a class you write it inside the class and you can access is from every instance of the class:
class Square {
var length: Double
func area() -> Double {
return length * length
}
}
But if you need to access the function from everywhere, then you don't write it inside a class. For example:
func squared(number: Int) -> Int {
return number * number
}
About your syntax issues between functions and methods: You guessed it right, methods and functions are called a little bit differently. That is because in Objective-C we had long method names and we liked them because we could read what the methods were doing and what the parameters were for. So the first parameter in a method is in most cases described by the function name itself. And the other parameters shouldn't only be some numbers or strings or instances, they should be described as well, so Swift writes the name of the variable automatically. If you want to describe it by yourself you can do that as well:
class Something {
func desc(firstString string1: String, secondString string2:String) {...}
}
Well, #Ricky's answer says it pretty much. I was confused what exactly they are. So here is my thought:
Functions could be defined outside of classes or inside of classes/structs/enums, while Methods have to be defined inside of and part of classes/structs/enums.
We could define a Function outside of any Type's definition and could use it within Methods of any Type's definition.
Just my understanding and illustration here, hope this helps someone else or you may edit if you feel there is an improvement needed OR let me know if anything is wrong:
//This is a Function which prints a greeting message based on the category defined in an 'enum'
func greet(yourName name: String, category: GreetingsCategory) {
switch category {
case .Person:
print("Hello, " + name + " Today is Tuesday")
case .Vehicle:
print("Hello, " + name + " your Vehicle is a Car")
}
}
//This is an 'enum' for greetings categories
enum GreetingsCategory: String {
case Person
case Vehicle
}
//Type: Person
class Person {
//This is a method which acts only on Person type
func personGreeting() {
greet(yourName: "Santosh", category: .Person)
}
}
//Type: Vehicle
class Vehicle {
//This is a method which acts only on Vehicle type
func vehicleGreeting() {
greet(yourName: "Santosh", category: .Vehicle)
}
}
//Now making use of our Function defined above by calling methods of defferent types.
let aPerson = Person()
aPerson.personGreeting()
//prints : Hello, Santosh Today is Tuesday
let aVehicle = Vehicle()
aVehicle.vehicleGreeting()
//prints: Hello, Santosh your Vehicle is a Car
//We can also call the above function directly
greet(yourName: "Santosh", category: .Person)
Mainly the names are used interchangeably without people having a real intent of distinguishing them. But ultimately they do have a difference.
someFile.swift:
func someFunc{
//some code
}
class someClass{
func someMethod{
//some code
}
}
Note: someClass != someFile
someMethod works only on its associated type which is 'someClass'. However the same can't be said for someFunc. someFunc is only in the someClass.Swift because semantically it is better suited to be written in that file. It could have been written in any other class as long as it's marked with private
And obviously the method can access self. With functions, there is no self.. For more see: What's the difference between a method and a function?
Here is a simple answer on the difference between functions and methods:
Some folks use “function” and “method” interchangeably, but there’s a
small difference: both of them are reusable chunks of code, but
methods belong to classes, structs, and enums, whereas functions do
not.
So:
func thisIsAFunction() {
}
struct Person {
func thisIsAMethod() {
}
}
Because methods always belong to a data type, they have a concept of
self that functions do not.
source: https://www.hackingwithswift.com/example-code/language/whats-the-difference-between-a-function-and-a-method
Lots of great answers, but let me use Xcode to show something visually from the UIKit module:
That is a function because it's written at the global level. It's not a method. Methods are scoped to a class.
Screenshot to show that it's at the global level.
The following function is at the global level:
public func UIApplicationMain(_ argc: Int32, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>>!,
_ principalClassName: String?, _ delegateClassName: String?) -> Int32
Icons for the different symbols. (Class, Method, Property, Protocol, Function, Extensions are all different symbols)
The function has an icon like 𝓯
The method has an icon of M
functional principle as a part of functional language
function is a first-class type (first-class citizen) in Swift. Higher order functions
assign to a variable
pass as an argument
return
Function
Function is a block of code that is created for executing some task. Function consists of name, optional parameters(name, type), optional return type, body.
func name(parameterName1: Int, parameterName2: String) -> Bool {
//statements
return true
}
Function type - function’s parameter type + return type[Java about]. For example it is used as function's parameter
//Function type for the sample above
(Int, String) -> Bool
Method
Method - is a function which is associated with a type - class, structure, enum [About]:
Instance method - method which belongs to instance
MyClass().foo()
Type method - method which belongs to type itself. class or static is used[About]
MyClass.foo()
Closure
As official doc says that Closure in Swift has three next forms:
global function(with name, without capturing) - is a function that is declared in a global scope(out of class scope). Usually it is defined as a first level of .swift file and does not have a big memory foot print
nested function(with name, with capturing enclosing function variables) - function inside other function
closure expression(without name, with capturing enclosing context)
Closure(closure expression) - anonymous function - is a block of code(functionality). Closure is a type of function without name. Closure is a function in terms of Functional programming. It can support capturing concept(if it doesn't capture it is lambda). It is similar to block in Objective-C.
[Closure vs Lambda]
They can be used for:
non-escaping closure - sync operations - click events, sort...
escaping closure - async operations - e.g.completion handler - it is a callback/notification which is called when task is done
class ClassA {
var variable = "Hello"
func fooA() {
print(variable)
let b = ClassB() //1
b.fooB(completionHandler: { [weak self] (input) -> String? in //2 pass closure //3 capture list or any calls from closure to outher scope
guard let self = self else { return nil }
self.variable = "World" //capturing self.variable
return String(input)
})
}
}
class ClassB {
var myCompletionHandler: ((Int) -> String?)? = nil //5
func fooB(completionHandler: #escaping (Int) -> String?) { //4
self.myCompletionHandler = completionHandler //6
let result = completionHandler(7)
}
func fooB2(completionHandler: #escaping (Int) -> String?) { //if you re-pass function to #escaping function you must mark it by #escaping too
self.fooB(completionHandler: completionHandler)
}
}
func testClosure() {
ClassA().fooA()
}
(Int) -> String? //Function type
//Closure Expression
{ [weak self] (input) -> String? in
//logic
}
[non-escaping vs escaping closure]
[#autoclosure]
[Init/customize stored property by closure]
[JVM Memory model]