void function not printing because cant return value but when i make string or int function it print null or return value at the end automatically - class

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.

Related

How come Flutter doesn't accept null checking within an 'if' statement [duplicate]

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 - !

compactMap() closure fails when adding irrelevant NOP declaration?

Playground
XCode Version 13.3 (13E113)
Swift 5.6
First print of compactMap() closure displays this:
["What\'s", "Going", "On?"]
The second print displays this:
[(), (), ()]
Seems like if I declare anything inside the closure, the output of the closure changes.
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
lineText
})
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
let _ : String
lineText
})
Is there a way to wrap some of it to hide the other declaration?
Is the closure confused about the type?
Is there any way to unconfuse it (or me)?
Is it a Swift bug?
Issue is root of why other things I'm trying to with this pattern aren't working.
UPDATE
As per #Shadowrun's answer below, I added a return statement in the 3rd example, but that leads to compile time errors. So is that resolvable?
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
let _ : String
return lineText
})
expression failed to parse:
error: test playground.playground:38:52: error: generic parameter 'ElementOfResult' could not be inferred
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
^
Swift.Sequence:2:28: note: in call to function 'compactMap'
#inlinable public func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]</b>
If you have a one line closure there's an implicit return, so the first one is returning lineText which is of type string. See "Functions With an Implicit Return" at https://docs.swift.org/swift-book/LanguageGuide/Functions.html
The second one doesn't actually return anything, once it is more than one line, there is no implicit return. So the return type is Void which is also spelled as the empty tuple, () and that's what you get there.
You need to say return lineText explicitly if you mean to return something.
This function:
{ idx, lineText in
let _ : String
lineText // This line evaluates the value of lineText and does nothing with the result
}
does not return a value. Any function that doesn't return a value returns a Void value. Void is a type with only one possible value, called (). Mapping to void is a pointless thing to do. Even if your function did a side effect, like printing something, it wouldn't be good style to use map just for side effects.
You can guard against this kind of mistake by being more explicit about the return type in the closure
{ idx, lineText -> String in ... }

Swift return different Types from a function

Completing some old HackerRank challenges.
Some of these appear to be broken - for example "Fair Rations" gives us the following function signature (note: The capital for the parameter is not my fault, it is not changeable within this context.
func fairRations(B: [Int]) -> Int {
// Enter code answer code here
}
Now the problem test cases (the details of the problem are not important here) require that we return an
Int
(i.e. 4) for some test cases, and a
String
(i.e. "NO") for other tests.
So I need to return either a String, or an Int depending upon my answers. I've tried to return an enum, but I can't make any changes to the HackerRank tests - also returning any
like:
func fairRations(B: [Int]) -> Any {
// Enter code answer code here
}
will not work as Any is not implicitly convertible to either a String or an Int.
The HackerRank problem is here: https://www.hackerrank.com/challenges/fair-rations/problem
To clarify in response to Joakim Danielson, the problem description implies that you can output "NO" to the console, but that is not actually true (see screenshot below).
Is it possible to have a function that returns both a String and an Int in Swift?
Just change the function to return a String. Keep in mind that integers can be represented as a string as well. The string "4" represents the number 4.
I changed the function to this in hacker rank:
func fairRations(B: [Int]) -> String {
return "4"
}
And it passed this test:
Basically,
If you want to return an integer x, just return x.description
If you want to return NO, just return "NO".
Both of the above values are strings.
Returning a String here works because the test calls the String(...) initialiser. And if you pass a string to that, it will still create the same string you passed in.
EDIT:
I tried editing the client code and it works. You can just return a Int? and do this:
if let result = fairRations(B: B) {
fileHandle.write(String(result).data(using: .utf8)!)
} else {
fileHandle.write("NO".data(using: .utf8)!)
}

How does the "return" keyword return a non-specified value when the return type is not specified? [Swift Playground]

Swift Playground provided the following code. The code's return causes the image placed upon touch to be spaced out. How does the function work when the return value is not specified and the return keyword is not followed with anything? Is there a default return value and type when nothing is not specified? Also when I tried out this code in Swift(the actual prog language on mac), the Touch type does not exist. Do I need to import a specific library for Swift Playground's code to work in Swift?
func addImage(touch: Touch) {
if touch.previousPlaceDistance < 50 {
return
}
let graphic = Graphic(image: ⭐️)
scene.place(graphic, at: touch.position)
}
The return here simply short-circuits the method so that it stops if the previousPlaceDistance is less than 50. It doesn't have to return a value; in fact, it can't return a value if no return type was specified for the function.
It is precisely this kind of short-circuiting where guard would be ideal, i.e.
guard touch.previousPlaceDistance >= 50 else {
return
}
This function does not need to return anything in the function definition. So simply calling return in enough in this case.
For example a function that need to return a string will look like this. In this case, you will have to return a string in your return statement. Functions without that -> ... line means that it returns nothing, or the so called void
func addImage(touch: Touch) -> String {
if touch.previousPlaceDistance < 50 {
return ""
}
...
}
For your second part of question, Touch is a class written in swift to provide some convenience when you playing around with swift playgound. However it does not exist in default swift library. A similar library can be UITouch and here is apple's document on that.
Where no explicit return type is given a function or method returns Void
The type of this function is () -> Void, or “a function that has no
parameters, and returns Void.”
The return of Void can be performed explicitly by writing return as in the function that you supply or implicitly (i.e. return is not written anywhere within the function or method).

Getting a function's return type in Swift

I realize that reflection isn't fully supported (yet) in Swift, but reflection run time methods are (apparently) supported. I'm trying to get the return type of a function at run time. Here's my example
let s:Selector = "willAnimateRotation"
var m:Method = class_getInstanceMethod(object_getClass(self), s)
let returnType = method_copyReturnType(m)
println("method: \(m); returnType: \(returnType)")
free(returnType)
Here's an example of my willAnimateRotation method, currently returning String:
private func willAnimateRotation() -> String {
return "abc"
}
The output of this does not seem to vary depending on the return type of the selector. E.g., with String or Void return type for the selector, I get the following output:
method: 0x0000000000000000; returnType: 0x0000000000000000
Thoughts?
ALSO: I'm actually not really trying to do this in Swift. I'm bridging an Objective-C class to Swift, and am getting the same results there, when the Objective-C code attempts to determine the return type of a Swift selector. That is, my end-goal in this case happens to be to use Objective-C to get the return type of a Swift selector.
OK. I've figured this out. The problem comes with my use of the "private" keyword. If you drop that and just use:
func willAnimateRotation() -> String {
return "abc"
}
The sample code above works fine.
In Swift you indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return.