#immutable
abstract class MyGithubReposState extends Equatable {
MyGithubReposState([List props = const []]) : super(props);
}
I have seen above code in one of the libraries I use. What does the [List props = const []] mean? List of list of props?
This is optional parameter as explained below.
A function can have two types of parameters:
required and optional.
The required parameters are listed first, followed by any optional parameters. Optional parameters can be named or positional.
Optional parameters can be either named or positional, but not both.
Named parameters
When calling a function, you can specify named parameters using paramName: value. For example:
this is calling of function
enableFlags(bold: true, hidden: false);
When defining a function, use {param1, param2, …} to specify named parameters:
this is how we define them
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
Positional parameters
Wrapping a set of function parameters in [] marks them as optional positional parameters:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
so that we can call this function by two way
Without optional positional parameter
say('Bob', 'Howdy')
With optional positional parameter
say('Bob', 'Howdy', 'smoke signal')
Reference here
[within this is optional] means these parameters are optional
From the official docs,
Wrapping a set of function parameters in [] marks them as optional positional parameters
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
Here’s an example of calling this function without the optional parameter:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
And here’s an example of calling this function with the third parameter:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
Related
When I set firstThing to default nil this will work, without the default value of nil I get a error that there is a missing parameter when calling the function.
By typing Int? I thought it made it optional with a default value of nil, am I right? And if so, why doesn't it work without the = nil?
func test(firstThing: Int? = nil) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
test()
Optionals and default parameters are two different things.
An Optional is a variable that can be nil, that's it.
Default parameters use a default value when you omit that parameter, this default value is specified like this: func test(param: Int = 0)
If you specify a parameter that is an optional, you have to provide it, even if the value you want to pass is nil. If your function looks like this func test(param: Int?), you can't call it like this test(). Even though the parameter is optional, it doesn't have a default value.
You can also combine the two and have a parameter that takes an optional where nil is the default value, like this: func test(param: Int? = nil).
The default argument allows you to call the function without passing an argument. If you don't pass the argument, then the default argument is supplied. So using your code, this...
test()
...is exactly the same as this:
test(nil)
If you leave out the default argument like this...
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
...then you can no longer do this...
test()
If you do, you will get the "missing argument" error that you described. You must pass an argument every time, even if that argument is just nil:
test(nil) // this works
Swift is not like languages like JavaScript, where you can call a function without passing the parameters and it will still be called. So to call a function in Swift, you need to assign a value to its parameters.
Default values for parameters allow you to assign a value without specifying it when calling the function. That's why test() works when you specify a default value on test's declaration.
If you don't include that default value, you need to provide the value on the call: test(nil).
Also, and not directly related to this question, but probably worth to note, you are using the "C++" way of dealing with possibly null pointers, for dealing with possible nil optionals in Swift. The following code is safer (specially in multithreading software), and it allows you to avoid the forced unwrapping of the optional:
func test(firstThing: Int? = nil) {
if let firstThing = firstThing {
print(firstThing)
}
print("done")
}
test()
You are conflating Optional with having a default. An Optional accepts either a value or nil. Having a default permits the argument to be omitted in calling the function. An argument can have a default value with or without being of Optional type.
func someFunc(param1: String?,
param2: String = "default value",
param3: String? = "also has default value") {
print("param1 = \(param1)")
print("param2 = \(param2)")
print("param3 = \(param3)")
}
Example calls with output:
someFunc(param1: nil, param2: "specific value", param3: "also specific value")
param1 = nil
param2 = specific value
param3 = Optional("also specific value")
someFunc(param1: "has a value")
param1 = Optional("has a value")
param2 = default value
param3 = Optional("also has default value")
someFunc(param1: nil, param3: nil)
param1 = nil
param2 = default value
param3 = nil
To summarize:
Type with ? (e.g. String?) is an Optional may be nil or may contain an instance of
Type
Argument with default value may be omitted from a call to
function and the default value will be used
If both Optional and has default, then it may be omitted from function call OR may be included and can be provided with a nil value (e.g. param1: nil)
in case you need to use a bool param, you need just to assign the default value.
func test(WithFlag flag: Bool = false){.....}
then you can use without or with the param:
test() //here flag automatically has the default value: false
test(WithFlag: true) //here flag has the value: true
"Optional parameter" means "type of this parameter is optional". It does not mean "This parameter is optional and, therefore, can be ignored when you call the function".
The term "optional parameter" appears to be confusing. To clarify, it's more accurate to say "optional type parameter" instead of "optional parameter" as the word "optional" here is only meant to describe the type of parameter value and nothing else.
If you want to be able to call the func with or without the parameter you can create a second func of the same name which calls the other.
func test(firstThing: Int?) {
if firstThing != nil {
print(firstThing!)
}
print("done")
}
func test() {
test(firstThing: nil)
}
now you can call a function named test without or without the parameter.
// both work
test()
test(firstThing: 5)
Don't let the question mark fools you!
Optional is an enum which has two cases:
#frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
code from the original compiled source of the Optional inside Xcode
When you are defining a function that accept some Type of arguments, you can pass a default value withe the same type.
in your case
the type of the firstThing is Optional<Int> (also known as Int?). So if you want the caller to the oportunity to ignore the paramter, you MUST do the job for the caller and pass a default value.
Usually we need the .none case of the optional so we can do:
func test(firstThing: Optional<Int> = .none) { ... }
This is exactly the same as:
func test(firstThing: Int? = nil) { ... }
Also!
Who seys that we the default value of an optional is a nil? maybe passing nil means that the function should remove something by updating it's value to 'nil'. So don't asume "the default value for optional is a nil"
It is little tricky when you try to combine optional parameter and default value for that parameter. Like this,
func test(param: Int? = nil)
These two are completely opposite ideas. When you have an optional type parameter but you also provide default value to it, it is no more an optional type now since it has a default value. Even if the default is nil, swift simply removes the optional binding without checking what the default value is.
So it is always better not to use nil as default value.
Default value doesn't mean default value of data type .Here default value mean value defined at the time of defining function.
we have to declare default value of variable while defining variable in function.
I'm upgrading a personal package that is based on the Flutter framework. I noticed here in the Flutter Text widget source code that there is a null check:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan! is still using the ! operator. Shouldn't textSpan be promoted to a non-nullable type without having to use the ! operator? However, trying to remove the operator gives the following error:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:
Error: A value of type 'String?' can't be returned from function 'myString' because it has a return type of 'String'.
Or if I try to get _mySting.length I get the following error:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
I thought doing the null check would promote _myString to a non-nullable type. Why doesn't it?
My question was solved on GitHub so I'm posting an answer below.
Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the ! operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? x;
double toDouble() {
if (x != null) return x.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar which extends Foo and overrides x field and implemented like this:
class Bar extends Foo {
#override
int? get x => (++_count).isOdd ? 1 : null;
int _count = 0;
}
Now, if you do
Bar().toDouble();
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?. There are generally 3 ways to do this.
Use local variable (Recommended)
double toDouble() {
final x = this.x; // <-- Use a local variable
if (x != null) return x.toDouble();
return -1;
}
Use ?. with ??
double toDouble() {
return x?.toDouble() ?? -1; // Provide a default value
}
Use null-assertion operator (!)
You should only use this solution when you're 100% sure that the variable (x) will never be null.
double toDouble() {
return x!.toDouble(); // Null assertion operator
}
style: Theme.of(context).textTheme.headline5!.copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using ? or a null safety checker - !
New to dart, take following code as example, //void function doesnt work and int/string function either returns null that is printed or value return which is automatically printed as can be seen in the output.
class Microphones{
String? name;
String? color;
int? model;
String printEverything(){
print(name);
return " ";
}
int? printint(){
print(model);
}
}
void main() {
var mic1=Microphones();
print(mic1.name);
mic1.name="Yeti";
mic1.color="black";
mic1.model=26;
print(mic1.name);
print(mic1.color);
print(mic1.model);
print(mic1.printEverything());
print(mic1.printint());
}
output:
null
Yeti
black
26
Yeti
26
null
i highly appreciate your replies/help in this regard.
All methods in Dart retuns null by default if you are not returning anything (either by having an empty return in methods specified to return void or not having any return at all in methods returning void or a nullable type like int?).
But return-type in the method signature specifies how the caller of the method should see the value. And here we have void which is described in the Dart language tour as:
A special type that indicates a value that’s never used.
https://dart.dev/guides/language/language-tour#a-basic-dart-program
So we specify void to signal to the user of our method, that the returned value should never be used. And the Dart analyzer and compiler will then try very hard to make sure you are not ending up using the returned value typed void.
Advanced section for the curious
But that does not mean it is impossible to use a returned value specified to be void by the method signature:
void someMethod() {
void someVoidVariable = 'Hey, I am a String!';
return someVoidVariable;
}
void someOtherMethod() => 'Hey, I am also a String!';
void main() {
print(someMethod() as String); // Hey, I am a String!
print(someOtherMethod() as String); // Hey, I am also a String!
}
In the first example, we force Dart to see our String as void. That is completely fine since all types can be seen as void. We are then allowed to return this void value since someMethod() is suppose to return void.
The reason for this forcing is that Dart would complain about (which makes sense because what we are doing is very much stupid and should never be in a real program):
void someMethod() {
return 'Hey, I am a String!';
// ERROR: A value of type 'String' can't be returned from the function
// 'someMethod' because it has a return type of 'void'.
}
Or this since we can't cast to void using as:
void someMethod() {
return 'Hey, I am a String!' as void; // ERROR: Expected a type name.
}
We are then casting that void back to a String to let Dart allow us to use the returned value in print() (since Dart otherwise would prevent us from trying to use the void typed value).
In the second example, I show the one of the reasons for why things are working like they does. In Dart, we can write these two method which are going to do the exact same (note I changed the return type to String for this example):
String someOtherMethod() {
return 'Hey, I am also a String!';
}
String someOtherMethod() => 'Hey, I am also a String!';
So the second way is a shorthand for if we just want to execute a single statement and return its value.
But what about:
void someOtherMethod() => 'Hey, I am also a String!';
If we followed the traditional rules, this would not be allowed since we cannot return a String since we have typed void. But sometimes, we also want to use this simple syntax to just execute a method and don't want to care about what that method would end up returning.
E.g. this:
final someList = <String>[];
void removeStringFromList(String string) => someList.remove(string);
Where the remove method on List is actually returning a bool which indicate if the element was inside the list.
So Dart ignores this problem when we use the => by just casting the result to void in this case. So in our last example, the returned bool is actually returned to the caller of removeStringFromList but because its type has been cast to void, the caller of removeStringFromList is prevented (in a lot of ways) from using the value.
I'm upgrading a personal package that is based on the Flutter framework. I noticed here in the Flutter Text widget source code that there is a null check:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan! is still using the ! operator. Shouldn't textSpan be promoted to a non-nullable type without having to use the ! operator? However, trying to remove the operator gives the following error:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:
Error: A value of type 'String?' can't be returned from function 'myString' because it has a return type of 'String'.
Or if I try to get _mySting.length I get the following error:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
I thought doing the null check would promote _myString to a non-nullable type. Why doesn't it?
My question was solved on GitHub so I'm posting an answer below.
Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the ! operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? x;
double toDouble() {
if (x != null) return x.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar which extends Foo and overrides x field and implemented like this:
class Bar extends Foo {
#override
int? get x => (++_count).isOdd ? 1 : null;
int _count = 0;
}
Now, if you do
Bar().toDouble();
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?. There are generally 3 ways to do this.
Use local variable (Recommended)
double toDouble() {
final x = this.x; // <-- Use a local variable
if (x != null) return x.toDouble();
return -1;
}
Use ?. with ??
double toDouble() {
return x?.toDouble() ?? -1; // Provide a default value
}
Use null-assertion operator (!)
You should only use this solution when you're 100% sure that the variable (x) will never be null.
double toDouble() {
return x!.toDouble(); // Null assertion operator
}
style: Theme.of(context).textTheme.headline5!.copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using ? or a null safety checker - !
I have the following method inside a User Class:
func Login(username: String, password: String) -> String
{
return "Login Success";
}
Why on Earth it only works calling it if I specify the second parameter "label"(not sure what it is called)?
var loginReturn = user.Login("aa", password: "zz");
iIf I do the following I got error:
var loginReturn = user.Login("aa", "zz");
I'm not happy with Swift.
From Functions in Swift
Function parameters have both an external parameter name and a local parameter name. An external parameter name is used to label arguments passed to a function call. A local parameter name is used in the implementation of the function.
(...)
By default, the first parameter omits its external name, and the second and subsequent parameters use their local name as their external name.
(...)
Omitting External Parameter Names
If you do not want to use an external name for the second or subsequent parameters of a function, write an underscore (_) instead of an explicit external name for that parameter.
I recommend you to read the whole chapter, it should clear up your confusion.
Also note that the external parameter names are technically a part of the function/method name.
You can write it like this:
func Login(username: String, _ password: String) -> String
{
return "Login Success";
}
For every method parameter you can define "inner" and "outer" parameters which will define the final look of the methods call.
If you call a function that has two parameters, you must list the name of the parameters after the first one if they have a name. With the current way you've written your function...
This Code Works
var loginReturn = login("aa", password: "zz")
And This Code Fails
var loginReturn = login("aa", "zz")