Cannot assign to a parameter - ios

I have declared a function
func someFunction(parameterName: Int) {
parameterName = 2 //Cannot assign to let value parameter Name
var a = parameterName
}
and trying to assign it a value during runtime, but it gives me error
"Cannot assign to let value parameter Name".
Is the parameter name constant by default? Can I change it to a variable?

[In Swift >= 3.0] Function parameters are defined as if by let and thus are constants. You'll need a local variable if you intend to modify the parameter. As such:
func someFunction (parameterName:Int) {
var localParameterName = parameterName
// Now use localParameterName
localParameterName = 2;
var a = localParameterName;
}
[In Swift < 3.0] Declare the argument with var as in:
func someFunction(var parameterName:Int) {
parameterName = 2;
var a = parameterName;
}
use of inout has a different semantics.
[Note that "variable parameters" will disappear in a future Swift version.] Here is the Swift documentation on "variable parameters":
Function parameters are constants by default. Trying to change the
value of a function parameter from within the body of that function
results in a compile-time error. This means that you can’t change the
value of a parameter by mistake.
However, sometimes it is useful for a function to have a variable copy of a parameter’s value to work with. You can avoid defining a
new variable yourself within the function by specifying one or more
parameters as variable parameters instead. Variable parameters are
available as variables rather than as constants, and give a new
modifiable copy of the parameter’s value for your function to work
with.
Define variable parameters by prefixing the parameter name with the keyword var: ..."
Excerpt From: Apple Inc. “The Swift Programming Language.”
If you actually want to change the value stored in a location that is passed into a function, then, as #conner noted, an inout parameter is justified. Here is an example of that [In Swift >= 3.0]:
1> var aValue : Int = 1
aValue: Int = 1
2> func doubleIntoRef (place: inout Int) { place = 2 * place }
3> doubleIntoRef (&aValue)
4> aValue
$R0: Int = 2
5> doubleIntoRef (&aValue)
6> aValue
$R1: Int = 4

In order to modify the argument passed in, you have to designate it as an inout parameter:
func someFunction(inout parameterName:Int)
{
parameterName = 2;
var a = parameterName;
}
Note this will change the variable that was passed in as well. If that isn't what you're looking for, use var as GoZoner suggested.

Related

Using init as a Closure

Recently I saw the following code line in a book (about CoreData)
return modelURLs(in: modelName).compactMap(NSManagedObjectModel.init)
I know what the code does but the question is: Why and how does it work?
There should be a closure as the argument of the compactMap function but there's only a "NSManagedObjectModel.init" in NORMAL parenthesis. What's the secret about it? What is it doing there? I would understand it if there's a static/class property called init which returns a closure but I don't think there is.
Unfortunately the book doesn't say more about this line of code. I would like to have further readings from the apple docs but I can't find anything. When I make a google search about "init in closures" then I don't get helpful results.
So you guys are my last hope :)
By the way: the function modelURLs(in: modelName) returns an Array of URLs but that's not really important here.
When using closures different syntax can be used as in the below example that converts an int array to a string array
let array = [1, 2, 3]
The following calls to compactMap will all correctly convert the array and generate the same result
let out1 = array.compactMap({return String($0)})
let out2 = array.compactMap({String($0)})
let out3 = array.compactMap {String($0)}
let out4 = array.compactMap(String.init)
When there are two init methods that takes the same number and types of argument then you must add the full signature for the init method to use. Consider this simple example struct
struct TwoTimesInt: CustomStringConvertible {
let value: Int
let twiceTheValue: Int
var description: String {
return "\(value) - \(twiceTheValue)"
}
init(value: Int) {
self.value = value
self.twiceTheValue = 2 * value
}
}
With only 1 init method we can do
let out5 = array.compactMap(TwoTimesInt.init)
But if we add a second init method
init(twiceTheValue: Int) {
self.value = twiceTheValue / 2
self.twiceTheValue = twiceTheValue
}
Then we need to give the full signature of the init method to use
let out6 = array.compactMap( TwoTimesInt.init(value:) )
Another thing worth mentioning when it comes to which method is selected is to look at the full signature of the init method including if it returns an optional value or not. So for example if we change the signature of the second init method to return an optional value
init?(twiceTheValue: Int) {
self.value = twiceTheValue / 2
self.twiceTheValue = twiceTheValue
}
then compactMap will favour this init since it expects a closure that returns an optional value, so if we remove the argument name in the call
let out7 = array.compactMap(TwoTimesInt.init)
will use the second init while the map function on the other hand will use the first init method if called the same way.
let out8 = array.map(TwoTimesInt.init)

Swift syntax discrepancy between parameters in initializer and functions

It seems to me that there is a discrepancy in Swift's syntax between calling an initializer and a function with at least one paremeter.
Let's consider these two examples:
class SimpleClass {
var desc: String
init(desc: String) {
self.desc = desc
}
}
let aClass = SimpleClass(desc: "description")
and
func simpleFunc(a: Int, b:Int) -> Int {
return a + b;
}
let aVal = simpleFunc(5, b: 6)
It seems odd to me that the compiler forces you to omit the first label in a function call, otherwise you will get an error "Extraneous argument label 'a:' in call". Whereas if we want to omit the first label during initilization, you get the error "Missing argument label 'desc:' in call".
The language guide says:
When calling a function with more than one parameter, any argument after the first is labeled according to its corresponding parameter name.
Source: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html
The arguments to the initializer are passed like a function call when
you create an instance of the class.
Source: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html
I'm new to Swift so I hope I didn't miss something, but this seems like a syntax discrepancy, because initializers/ constructors are just kind of functions and forcing to omit the first label in a function call seems inconsistent to me.
That's because Swift focuses on readability; function calls to be able to be read like a sentence. See this, specifically the section on "Local and External Parameter Names for Methods". Your function, to comply with this style, should be more like:
func add(a: Int, to b: Int) -> Int {
return a + b
}
let c = add(1, to: 2)

Assigning Closure to variable in Swift causes 'variable used before being initialized'

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.

How to explicitly specify variables as type dynamic?

dynamic x = 2;
This doesn't compile. But:
final int n = 6; /* and */
final y = "Hello world!"
both compile.
Is it possible and how to declare variables explicitly as of type dynamic?
It is possible to declare variables explicitly as being type dynamic. The code
dynamic x = 2;
compiles and is equivalent to the code
var x = 2;
var is shorthand for dynamic when declaring variables. Omitting a type annotation is equivalent to making the type annotation dynamic.
The difference between var and dynamic is that var is for declaring variables and is not a type; it cannot be the return type of a function (since that is not declaring a variable) and function arguments can omit the keyword var (the declaration f(x){} is equivalent to the declarations f(dynamic x){} and f(var x){}).
You only need to explicitly use dynamic in type parameters for generic classes where at least one but not all type parameters are dynamic, such as Map<String, dynamic>.
var x = 2; defines a variable without explicit type, which is the same as dynamic.

Difference between "var" and "dynamic" type in Dart?

According to this article:
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
So, what is the difference between dynamic and var? When to use?
dynamic is a type underlying all Dart objects. You shouldn't need to explicitly use it in most cases.
var is a keyword, meaning "I don't care to notate what the type is here." Dart will replace the var keyword with the initializer type, or leave it dynamic by default if there is no initializer.
Use var if you expect a variable assignment to change during its lifetime:
var msg = "Hello world.";
msg = "Hello world again.";
Use final if you expect a variable assignment to remain the same during its lifetime:
final msg = "Hello world.";
Using final (liberally) will help you catch situations where you accidentally change the assignment of a variable when you didn't mean to.
Note that there is a fine distinction between final and const when it comes to objects. final does not necessarily make the object itself immutable, whereas const does:
// can add/remove from this list, but cannot assign a new list to fruit.
final fruit = ["apple", "pear", "orange"];
fruit.add("grape");
// cannot mutate the list or assign a new list to cars.
final cars = const ["Honda", "Toyota", "Ford"];
// const requires a constant assignment, whereas final will accept both:
const names = const ["John", "Jane", "Jack"];
dynamic: can change TYPE of the variable, & can change VALUE of the variable later in code.
var: can't change TYPE of the variable, but can change VALUE of the variable later in code.
final: can't change TYPE of the variable, & can't change VALUE of the variable later in code.
dynamic v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // changing type of v from int to String.
var v = 123; // v is of type int.
v = 456; // changing value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
final v = 123; // v is of type int.
v = 456; // ERROR: can't change value of v from 123 to 456.
v = 'abc'; // ERROR: can't change type of v from int to String.
try this in DartPad:
void main() {
dynamic x = 'hal';
x = 123;
print(x);
var a = 'hal';
a = 123;
print(a);
}
you can change the type of x, but not a.
var, like final, is used to declare a variable. It is not a type at all.
Dart is smart enough to know the exact type in most situations. For example, the following two statements are equivalent:
String a = "abc"; // type of variable is String
var a = "abc"; // a simple and equivalent (and also recommended) way
// to declare a variable for string types
On the other hand, dynamic is a special type indicating it can be any type (aka class). For example, by casting an object to dynamic, you can invoke any method (assuming there is one).
(foo as dynamic).whatever(); //valid. compiler won't check if whatever() exists
(foo as var).whatever(); //illegal. var is not a type
var a ;
a = 123;
print(a is int);
print(a);
a = 'hal';
print(a is String);
When defined without initial value, var is dynamic
var b = 321;
print(b is int);
print(b);
//b = 'hal'; //error
print(b is String);
When defined with initial value, var is int in this case.
To clarify some of the previous answers, when you're declaring a variable as dynamic, it's type changes depending on what you assign to it. When you're declaring a var, the type is set once it's assigned something, and it cannot be changed after that.
For example, the following code:
dynamic foo = 'foo';
print('foo is ${foo.runtimeType} ($foo)');
foo = 123;
print('foo is ${foo.runtimeType} ($foo)');
will return the following result when run in DartPad:
foo is String (foo)
foo is int (123)
But the following code won't even compile:
var bar = 'bar';
print('bar is ${bar.runtimeType} ($bar)');
bar = 123; // <-- Won't compile, because bar is a String
print('bar is ${bar.runtimeType} ($bar)');
Long story short - use dynamic if you want a non-typed variable, use var when you want a typed variable with whatever type you assign to it.
Looking at the previous answers I hope this can clarify/summarize everything:
There are the keywords var, final, and const. These are to declare a variable (to indicate its existence) (Side note: Declaration vs Initialization)
Then there are types like String, int, List, dynamic, etc. (The type indicates what kind of value the variable should hold, this is for type safety)
Usually, we declare a variable by explicitly stating its type:
String a; // a is now a String type
int b; // b is now an int type
But we can also use the var keyword. By default, this sets the type of the variable to whatever it is initialized with. (This is called type inference)
var a = "hello"; // a is now a String type
var b = 5; // b is now an int type
Now what happens when you try to declare a variable with the var keyword, but don't initialize a value? How is it supposed to infer a type? Well, there is also a type called dynamic. This is different than the usual String or int in the sense that it allows for the variable to be assigned a value of any type (Usually there will be an error).
String a = "hello"; // a is now a String type
// var a = "hello"; // Alternative way; same as the line above because its type is inferred to be String
a = 5 // error: A value of type 'int' can't be assigned to a variable of type 'String'
dynamic b; // b is now a dynamic type
b = "hello"; // still a dynamic type, but now its value is of type String (You can use b.runtimeType to check)
b = 5; // dynamic type, but now its value is of type int
So to address the original confusion regarding the quote from the article,
As you might know, dynamic (as it is now called) is the stand-in type when a static type annotation is not provided.
It just means that if you don't explicitly state its type (you use var to declare a variable) and do so without initialization, it simply infers its type as dynamic:
var b; // b is now a dynamic type, the following will not have any errors.
b = "hello";
b = 5;
b = true;
Other notes:
Not sure why people started talking about final and const, but I think the accepted answer here explains it well if you want to know more.
dynamic a; and var a; is effectively the same: They both declare a variable of dynamic type.
Two ways of checking the type of a variable is using the is operator and using .runtimeType which works differently. See the following example:
dynamic b; // b is now a dynamic type, no value
print(b is dynamic); // true
print(b is Null); // true
print(b is String); // false
print(b is int); // false
print(b.runtimeType); // Null
b = "hello"; // dynamic type, String value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // true
print(b is int); // false
print(b.runtimeType); // String
b = 5; // dynamic type, int value
print(b is dynamic); // true
print(b is Null); // false
print(b is String); // false
print(b is int); // true
print(b.runtimeType); // int
One of aspect than can consider in comparison dynamic vs var is taking into account behavior when using var declaration with initialization at the same time there is not possibility to change type which in case of dynamic is.
But dynamic vs var is not the question what I would ask.
I would ask more what is difference between dynamic vs Object.
Here is a DO annotate with Object instead of dynamic to indicate any object is allowed.
It is hard to feel it at the beginning, but dynamic I would relate to generic type argument.
Both in dynamic and var,the variable can hold data of any data type, i.e., int , float,string,etc
If a variable is declared as a dynamic and if even initialised, its type can change over time.Try this code in https://dartpad.dev/
void main() {
dynamic x = 'abc';
x = 12345;
print(x);
}
If you declare variable as a var, once assigned type can not change.
void main() {
var x = 'abc';
x = 12345;
print(x);
}
The above code will result in the error stating that A value of type 'int' can't be assigned to a variable of type 'String' - line 3
BUT, if you state a var without initializing, it becomes a dynamic:
void main() {
var x ;
x = 'abc';
x=12345;
print(x);
}
A dynamic variable can change his type and a var type can't be changed.
For example :
var myVar = 'hello';
dynamic myDynamicVar = 'hello';
myVar = 123; // not possible
myDynamicVar = 123; // possible
dynamic is a data type that indicates all data types in dart
var is a variable declaration way like "final" that takes the data type of its value
If you use var you can't change the data type of the variable. But if you use dynamic you can change it freely.
for ex.
dynamic x = 12; // type: integer
x= "Hello world"; // type: string
This will work with no issues if you do the same using var instead of dynamic you will get an error since you can't change the data type because it is automatically assigned to the variable when initialized.
dynamic: can change the TYPE of the variable, & can change the VALUE of the variable later in the code.
var: can't change the TYPE of the variable, but can change the VALUE of the variable later in code

Resources