I am subclassing a uiscrollview and in the layoutSubviews method I have the following
let v = self.delegate?.viewForZoomingInScrollView!(self)
let f = v?.frame
if f != nil {
f!.origin.x = 100
}
I'm getting the error:
Cannot assign to the result of this expression
on the line
f!.origin.x = 100
Where am I going wrong
in your code f is declared as an immutable variable. Immutable variables cannot be changed after initial assignment at declaration.
let variable_name = 10
variable_name = 11 // Cannot assign to let value 'v'
The let keyword is used to declare immutable variables.
The var keyword is used to declare mutable variables.
var variable_name = 10
variable_name = 14 // Can be changed
So change your code to var f = v?.frame.
Also if you trying to modify the frame of the view, it will only work if you directly assign to the view?.frame.origin.x = 100, since the above code will only create a copy of the frame in f.
Because f is declared as let and immutable.
Related
I have a problem with a closure that is meant to be created and then being executed within another function over the range of the 2D pixel raster of an image where it shall basically called like this:
filter(i,j) and return a value based on its arguments.
I thought this code should work but it complains that the closure variable I have created is not initialized. I guess that means that I did not gave it arguments, but I wont within this function as the data is known to the closure at the time when it interacts with the image. How can I setup a closure which does not care about initialization?
Thank you in advance :)
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var closure:(i:Int, j:Int)->Int
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
closure = filter
}
//other if statements with different closure definitions follow...
//This call throws error: variable used before being initialized
let image = filterImage(closure)
}
You use the variable closure before the compiler is certain that it is initialized. You can solve this in 2 ways, depending on what you need:
Add an else-clause to your if and set closure to a default closure.
Make closure optional by defining it as var closure: ((i: Int, j: Int) -> Int)? and then you can check if it is optional before using it by using closure?(i, j) or if let filter = closure { filter(i, j)}.
Also, try to use better variable names such as filterClosure. closure on its own doesn't really say much.
The problem is that you define your closure as:
var closure:(i:Int, j:Int)->Int
Then you initialize it only if you enter the if
If not, that var is not initialized, hence the compiler warning
Possible solution:
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var filterClosure:((i:Int, j:Int)->Int)?
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
filterClosure = filter
}
//other if statements with different closure definitions follow...
if let closure = filterClosure {
let image = filterImage(closure)
}
}
Your closure is only initialized if the code enters your if block (i.e. if type == FilterType.MyFilter). In the other case it is left uninitialized.
I made a new Playground and wrote the code as following.
var value = 33 //This will make an integer type of value variable with value 33
value = 22.44 //This doesn't execute as its assigning Double/Float value to an integer.
I tried
1.
value = Double(value)
value = 44.55 //Error here
2.
value = Double(33.44) //Error here too.
3.
value : Double = 33.22 //Error here too.
Now what should I do to assign floating point to value.
NOTE: I am at learning level in Swift.
Thanks.
Declaring var value = 33 will infer the type of value as Int. If you want to assign 33 and make value as Float or Double, you have to declare the type var value : Double = 33 or convert 33 to a Double while assign var value = Double(33).
You must set the data type within the variable declaration.
var value: Double = 33
But you could also do it like so:
var value: Double
value = 33
Defining it as a var will make the variable mutable, so after defining you can change the value
value = 33.2
value = 46.1
If you are only defining a constant, or a variable which does not need to change, you're best defining it like so:
let value: Double = 33.2
If you need this to be an Int for any reason at some point you can pass it through to a function or define it like so:
let intValue = Int(value)
With the first line
var value = 33
you created a variable with the type of Int (because 33 is an integer literal). After that, you cannot assign any other type to that, only Ints. You should create another variable to store the result of the convertion.
In FSI I type
> let a = 10;;
val a : int = 10
> let a = a + 1;;
val a : int = 11
Looks like I have a mutable variable here? Am I missing something?
It is not a mutable value. But you use the shadowing : in F#, value shadowing occurs when a variable declared within a certain scope (decision block, method, or inner class) has the same name as a variable declared in an outer scope.
If you want to have a mutable value, there is a syntaxe in F# :
let mutable a = 10
a <- a + 1
As already explained by Arthur, what you see is shadowing which means that the original "variable" named a is hidden by a new "variable" also named a (I use variable in quotes, because they are actually immutable values).
To see the difference, you can capture the original value in a function and then print the value after hiding the original value:
> let a = 10;; // Define the original 'a' value
val a : int = 10
> let f () = a;; // A function captures the original value
val f : unit -> int
> let a = 42;; // Define a new value hiding the first 'a'
val a : int = 42
> f();; // Prints the original value - it is not mutated!
val it : int = 10
Sadly, you cannot use exactly the same code to see how let mutable behaves (because F# does not allow capturing mutable references in closures), but you can see mutation when you use reference cells (that is, a simple object that stores mutable value in the heap):
> let a = ref 10;; // Create a mutable reference cell initialized to 10
val a : int ref = {contents = 10;}
> let f () = !a;; // A function reads the current value of the cell
val f : unit -> int
> a := 42;; // Overwrite the value in the cell with 42
val it : unit = ()
> f();; // Prints the new value - it is mutated
val it : int = 42
You can run the code line-by-line in F# interactive, but it will do exactly the same thing when you copy the entire snippet (the input lines) and place them in normal F# code - e.g. inside a function or a module. The ;; is just to end the line in the F# interactive input (I typed the code in the F# Interactive window), but it is not needed in normal code, because F# uses indentation to find out where a statement ends.
Why is disabled types like
type t = A of int | B of string * mutable int
while such types are allowed:
type t = A of int | B of string * int ref
The question is, how would you modify the value of a mutable element of discriminated union case? For ref types, this is quite easy, because ref is a reference cell (a record actually) which contains the mutable value:
match tval with
| B(str, refNum) -> refNum := 4
We extract the reference cell and assign it to a new symbol (or a new variable) refNum. Then we modify the value inside the ref cell, which also modifies tval, because the two references to the cell (from discriminated union case and from refNum variable) are aliased.
On the other hand, when you write let mutable n = 0, you're creating a variable, which can be directly mutated, but there is no cell holding the mutable value - the variable n is directly mutable. This shows the difference:
let mutable a = 10
let mutable b = a
b <- 5 // a = 10, b = 5
let a = ref 10
let b = a
b := 5 // a = 5, b = 5 (because of aliasing!)
So, to answer your question - there is no way to directly refer to the value stored inside the discriminated union case. You can only extract it using pattern matching, but that copies the value to a new variable. This means that there isn't any way you could modify the mutable value.
EDIT
To demonstrate limitations of mutable values in F#, here is one more example - you cannot capture mutable values inside a closure:
let foo() =
let mutable n = 0
(fun () -> n <- n + 1; n) // error FS0407
I think the reason is same as with discriminated union cases (even though it's not as obvious in this case). The compiler needs to copy the variable - it is stored as a local variable and as a field in the generated closure. And when copying, you want to modify the same variable from multiple references, so aliasing semantics is the only reasonable thing to do...
Ref is a type (int ref = ref<int>). Mutable is not a type, it's a keyword that allows you to update a value.
Example:
let (bla:ref<int>) = ref 0 //yup
let (bla:mutable<int>) = 3 //no!
I am attempting to write some simple code in F#, and i get this error:
Error 1 The mutable variable 'i' is used in an invalid way. Mutable variables may not be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via 'ref' and '!'
Code:
let printProcess = async {
let mutable i = 1;
while true do
System.Console.WriteLine(i);//error is here
i <- i + 1;
}
Why won't it let me print the variable?
You can't refer to mutables inside a closure, and that includes such constructs as seq{} and async{} blocks.
You could write
let printProcess = async {
let i = ref 1
while true do
System.Console.WriteLine(!i)
i := !i + 1
}
See this blog for some discussion.