Dart null / false / empty checking: How to write this shorter? - if-statement

This is my code for true on everything but empty string, null and false:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false) {
// do sth ...
}
This is my code for true on everything but empty string, null, false or zero:
if (routeinfo["no_route"] == "" || routeinfo["no_route"] == null || routeinfo["no_route"] == false || routeinfo["no_route"] == 0) {
// do sth...
}
How can I write this shorter in Dart? Or is it not possible?

If your requirement was simply empty or null (like mine when I saw this title in a search result), you can use Dart's safe navigation operator to make it a bit more terse:
if (routeinfo["no_route"]?.isEmpty ?? true) {
//
}
Where
isEmpty checks for an empty String, but if routeinfo is null you can't call isEmpty on null, so we check for null with
?. safe navigation operator which will only call isEmpty when the object is not null and produce null otherwise. So we just need to check for null with
?? null coalescing operator
If your map is a nullable type then you have to safely navigate that:
if (routeinfo?["no_route"]?.isEmpty ?? true) {
//
}

You could do
if (["", null, false, 0].contains(routeinfo["no_route"])) {
// do sth
}

Late 2020 Update
Summary
This answer holds true, except for isNull and isNotNull. They no longer provide type promotion when Null Safety is introduced in dart/flutter in the future.
Other helpers like isNullOrEmpty do not provide type promotion, as they are in a different (sub-)scope compared to callsite.
My personal opinion, is that you can drop isNull and isNotNull but keep other helpers as you shouldn't expect them to do type promotion for you.
Explanation
This is because Null Safety was finally introduced in Dart/Flutter. But as of October 2020, this feature is still not available for stable releases on dart/flutter. Check out the quick guide Null Safety or the thorough Understanding Null Safety.
Null Safety in Dart/Flutter should be similar to Swift (Optional) and Kotlin (Nullable Types, Non-Nullable Types).
Demonstration
Here's a demonstration why encapsulation/helper-getter of isNull (== null) and isNotNull (!= null) is a very big problem:
// Promotion works
int definitelyInt(int? aNullableInt) {
if (aNullableInt == null) { // Promote variable `aNullableInt` of Nullable type `int?` to Non-Nullable type `int`
return 0;
}
return aNullableInt; // Can't be null! This variable is promoted to non-nullable type `int`
}
When "Null Safety" is shipped in the dart release you are using, the type promotion in above code works! HOWEVER:
// Promotion does NOT work!!!
int definitelyInt(int? aNullableInt) {
if (aNullableInt.isNull) { // does NOT promote variable `aNullableInt` of Nullable type `int?`
return 0;
}
return aNullableInt; // This variable is still of type `int?`!!!
}
The above doesn't work, because the null check == null and != null are encapsulated in a sub-scope (different stack frame) and not inferred to have this "promotion" effect within definitelyInt scope.
Early 2020 Update
Here's a modified version using getters instead of instance/class methods and covering whitespaces, isNull, and isNotNull.
Second Update
It also accounts for empty lists and maps now!
Third Update
Added private getters for safety and modularity/maintainability.
Fourth Update
Updated the answer to fix a particular problem with Map, it's not correctly being handled when empty! Because Map is not an Iterable. Solved this issue by introducing _isMapObjectEmpty U
Solution
extension TextUtilsStringExtension on String {
/// Returns true if string is:
/// - null
/// - empty
/// - whitespace string.
///
/// Characters considered "whitespace" are listed [here](https://stackoverflow.com/a/59826129/10830091).
bool get isNullEmptyOrWhitespace =>
this == null || this.isEmpty || this.trim().isEmpty;
}
/// - [isNullOrEmpty], [isNullEmptyOrFalse], [isNullEmptyZeroOrFalse] are from [this StackOverflow answer](https://stackoverflow.com/a/59826129/10830091)
extension GeneralUtilsObjectExtension on Object {
/// Returns true if object is:
/// - null `Object`
bool get isNull => this == null;
/// Returns true if object is NOT:
/// - null `Object`
bool get isNotNull => this != null;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`s
/// - empty `Iterable` (list, set, ...)
/// - empty `Map`
bool get isNullOrEmpty =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
bool get isNullEmptyOrFalse =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse;
/// Returns true if object is:
/// - null `Object`
/// - empty `String`
/// - empty `Iterable` (list, map, set, ...)
/// - false `bool`
/// - zero `num`
bool get isNullEmptyFalseOrZero =>
isNull ||
_isStringObjectEmpty ||
_isIterableObjectEmpty ||
_isMapObjectEmpty ||
_isBoolObjectFalse ||
_isNumObjectZero;
// ------- PRIVATE EXTENSION HELPERS -------
/// **Private helper**
///
/// If `String` object, return String's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `String`
bool get _isStringObjectEmpty =>
(this is String) ? (this as String).isEmpty : false;
/// **Private helper**
///
/// If `Iterable` object, return Iterable's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Iterable`
bool get _isIterableObjectEmpty =>
(this is Iterable) ? (this as Iterable).isEmpty : false;
/// **Private helper**
///
/// If `Map` object, return Map's method `isEmpty`
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `Map`
bool get _isMapObjectEmpty => (this is Map) ? (this as Map).isEmpty : false;
/// **Private helper**
///
/// If `bool` object, return `isFalse` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `bool`
bool get _isBoolObjectFalse =>
(this is bool) ? (this as bool) == false : false;
/// **Private helper**
///
/// If `num` object, return `isZero` expression
///
/// Otherwise return `false` to not affect logical-OR expression. As `false` denotes undefined or N/A since object is not `num`
bool get _isNumObjectZero => (this is num) ? (this as num) == 0 : false;
}
Assumptions
This presumes Dart 2.7 or above to support Extension Methods.
Usage
The above are two Extension classes. One for Object and one for String. Put them in a file separately/together and import the files/file at callsite file.
Description
Coming from Swift, I tend to use extensions like user #Benjamin Menrad's answer but with getter instead of method/function when applicable -- mirroring Dart's computed properties like String.isEmpty.
Coming from C#, I like their String's helper method IsNullOrWhiteSpace.
My version merges the above two concepts.
Naming
Rename the Extension classes whatever you like. I tend to name them like this:
XYExtension
Where:
X is File/Author/App/Unique name.
Y is name of Type being extended.
Name examples:
MyAppIntExtension
DartDoubleExtension
TextUtilsStringExtension
OHProviderExtension
Criticism
Why private getters instead of simple
this == null || this == '' || this == [] || this == 0 || !this
I think this is safer as it first casts the object to the right type we want to compare its value to.
More modular as changes are central within the private getters and any modification is reflected everywhere.
If type check fails within the private getter, we return false which doesn't affect the outcome of the root logical-OR expression.

I would write a helper function instead of doing everything inline.
bool isNullEmptyOrFalse(Object o) =>
o == null || false == o || "" == o;
bool isNullEmptyFalseOrZero(Object o) =>
o == null || false == o || 0 == o || "" == o;
That avoids the repeated lookup (like the contains operation), but it is much more readable. It also doesn't create a new List literal for each check (making the list const could fix that).
if (isNullEmptyOrFalse(routeinfo["no_route"])) { ... }
When struggling with making something short and readable, making a well-named helper function is usually the best solution.
(Addition: Now that Dart has extension methods, it's possible to add the functionality as methods or getters that are seemingly on the object, so you can write value.isNullOrEmpty directly).

As coming from Android and Kotlin, I prefer extension methods over a static helper method. And with Dart 2.7 you can now use that as well:
extension Extension on Object {
bool isNullOrEmpty() => this == null || this == '';
bool isNullEmptyOrFalse() => this == null || this == '' || !this;
bool isNullEmptyZeroOrFalse() =>
this == null || this == '' || !this || this == 0;
}
Now you can just call these methods from anywhere in your code:
if (anyVariable.isNullOrEmpty()) {
// do something here
}
You might need to manually import the dart class, where you put your extension methods, for example:
import 'package:sampleproject/utils/extensions.dart';

With Null safety:
Say, you have a nullable Map and a List which have nullable values in it.
Map<String, List?>? map;
List<String?>? list;
To check if the collection is neither null nor empty, you can do:
if (map?.containsKey('foo') ?? false) {
print('map is not-null, and key "foo" is present.');
}
if (list?.isNotEmpty ?? false) {
print('list is not-null and not empty');
}

For strings i like this approach:
extension NullableStringExtensions<E> on String? {
/// Returns `true` if this string is `null` or empty.
bool get isNullOrEmpty {
return this?.isEmpty ?? true;
}
/// Returns `true` if this string is not `null` and not empty.
bool get isNotNullNorEmpty {
return this?.isNotEmpty ?? false;
}
}
Credits go to the author of this package: https://pub.dev/packages/string_ext

bool isNullString(String? value) {
if (value == null || value.isEmpty ) {
return true;
} else {
return false;
}
}
and use this method like
isNullString(yourValue)

package:quiver has an isEmpty function that returns true if the argument is null or the empty string.
It's also trivial to implement such a function yourself.

Related

Regex or Wildcard in Kotlin's when statement?

I'm working on a RESTful app in Kotlin and for the router, I'm using a when statement, as it's the most readable and good looking conditional.
Is there a way to use Regex or a wildcard in the when statement for a string?
(So that URIs like "/article/get/" would all be passed to the same controller)
The structure of my router is as follows:
when(uri) {
"some/url" -> return SomeController(config).someAction(session)
}
Yes.
import kotlin.text.regex
val regex1 = Regex( /* pattern */ )
val regex2 = Regex( /* pattern */ )
/* etc */
when {
regex1.matches(uri) -> /* do stuff */
regex2.matches(uri) -> /* do stuff */
/* etc */
}
You could also use containsMatchIn if that suits your needs better than matches.
Explanation:
The test expression of a when statement is optional. If no test expression is included, then the when statement functions like an if-else if chain, where the whenCondition of each whenEntry shall independently evaluate to a boolean.
EDIT:
So I thought about it for awhile, and I came up with a different approach that might be closer to what you want.
import kotlin.text.regex
when (RegexWhenArgument(uri)) {
Regex(/* pattern */) -> /* do stuff */
Regex(/* pattern */) -> /* do stuff */
/* etc */
}
Where RegexWhenArgument is minimally defined as:
class RegexWhenArgument (val whenArgument: CharSequence) {
operator fun equals(whenEntry: Regex) = whenEntry.matches(whenArgument)
override operator fun equals(whenEntry: Any?) = (whenArgument == whenEntry)
}
This approach lets you get as close as possible to the "argument-ful" when expression syntax. I think it's about as streamlined and readable as it can be (assuming that you define the RegexWhenArgument class elsewhere).
This approach uses something similar to the visitor design pattern in combination with Kotlin's operator overloading to redefine what constitutes a "match" between a when expression argument and a whenEntry. If you really wanted to, I suppose you could take this approach a step further and generify RegexWhenArgument into a general-purpose WhenArgument and WhenArgumentDecorator that allows you to specify custom "match" criteria in a when expression for any sort of type, not just Regex.
The typing of the when statement enforces to have compatible types between the whenSubject and the whenEntries. So we cannot compare a String whenSubject with a Regex directly.
We can use when with no subject, then branch conditions may be simply boolean expressions.
fun main() {
val uri: String? = "http://my.site.com/a/b/c"
val res = when {
uri == null -> "NULL"
uri == "http://my.site.com/" -> "ROOT"
uri.startsWith("http://my.site.com/a/") -> "A STUFF"
uri.matches(Regex("http://my.site.com/b/.*")) -> "B STUFF"
else -> "DEFAULT"
}
/* do stuff */
}
Alternatively, we can emulate a kind of when+regex with a dedicated class and few helper functions.
fun main() {
val uri: String? = "http://my.site.com/a/b/c"
val res2 = when(matching(uri)) {
null -> "NULL"
matchesLiteral("http://my.site.com/") -> "ROOT"
matchesRegex("http://my.site.com/a/.*") -> "A STUFF"
else -> "DEFAULT"
}
/* do stuff */
}
class MatchLiteralOrPattern(val value: String, val isPattern: Boolean) {
override fun equals(other: Any?): Boolean {
if (other !is MatchLiteralOrPattern) return false
if (isPattern && !other.isPattern) return Regex(this.value).matches(other.value)
if (!isPattern && other.isPattern) return Regex(other.value).matches(this.value)
return value == other.value
}
}
fun matching(whenSubject: String?) = whenSubject?.let { MatchLiteralOrPattern(it, false) }
fun matchesLiteral(value: String) = MatchLiteralOrPattern(value, false)
fun matchesRegex(value: String) = MatchLiteralOrPattern(value, true)
I tried the following on the kotlin playground and it seems to work as expected.
class WhenArgument (val whenArg: CharSequence) {
override operator fun equals(other: Any?): Boolean {
return when (other) {
is Regex -> other.matches(whenArg)
else -> whenArg.equals(other)
}
}
}
fun what(target: String): String {
return when (WhenArgument(target) as Any) {
Regex("source-.*") -> "${target} is-a-source"
Regex(".*-foo") -> "${target} is-a-foo"
"target-fool" -> "${target} is-the-target-fool"
else -> "nothing"
}
}
fun main() {
println(what("target-foo"))
println(what("source-foo"))
println(what("target-bar"))
println(what("target-fool"))
}
It works around the type compatibility problem by making the 'when' argument of type Any.

this.get('x') returns ' undefined' instead of 'undefined'

In a form-component I have an observer that tests if a property is valid before to start further validations.
So I checked if the property has not yet been defined (happens at initialization f.e.)
if(typeof this.get('myProperty') !== 'undefined') {
//do smth
}
Then I realized that this.get would not return a type of 'undefined' but a string with the value undefined.
Fair enough.
BUT
console.log(this.get('myProperty'));
gives me ' undefined' instead of 'undefined' - notice the space before 'undefined'!
Is this a bug?
Or do I really have to check for ' undefined' with a space and is there a reason for that?
Ember-cli: 1.13.7
Ember: 2.0.1
How about you use Ember.isNone or Ember.isEmpty. For the opposite Ember.isPresent
Returns true if argument is null or undefined.
Ember.isNone(); // true
Ember.isNone(null); // true
Ember.isNone(undefined); // true
Ember.isNone(''); // false
Ember.isNone([]); // false
Ember.isNone(function(){}); // false
This utility function constrains the rules on Ember.none by returning false for empty string and empty arrays.
Ember.isEmpty(); // true
Ember.isEmpty(null); // true
Ember.isEmpty(undefined); // true
Ember.isEmpty(''); // true
Ember.isEmpty([]); // true
Ember.isEmpty('tobias fünke'); // false
Ember.isEmpty([0,1,2]); // false

java.lang.AssertionError: expected

My TestNG test implementation throws an error despite the expected value matches with the actual value.
Here is the TestNG code:
#Test(dataProvider = "valid")
public void setUserValidTest(int userId, String firstName, String lastName){
User newUser = new User();
newUser.setLastName(lastName);
newUser.setUserId(userId);
newUser.setFirstName(firstName);
userDAO.setUser(newUser);
Assert.assertEquals(userDAO.getUser().get(0), newUser);
}
The error is:
java.lang.AssertionError: expected [UserId=10, FirstName=Sam, LastName=Baxt] but found [UserId=10, FirstName=Sam, LastName=Baxt]
What have I done wrong here?
The reason is simple. Testng uses the equals method of the object to check if they're equal. So the best way to achieve the result you're looking for is to override the equals method of the user method like this.
public class User {
private String lastName;
private String firstName;
private String userId;
// -- other methods here
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!User.class.isAssignableFrom(obj.getClass())) {
return false;
}
final User other = (User) obj;
//If both lastnames are not equal return false
if ((this.lastName == null) ? (other.lastName != null) : !this.lastName.equals(other.lastName)) {
return false;
}
//If both lastnames are not equal return false
if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName)) {
return false;
}
//If both lastnames are not equal return false
if ((this.userId == null) ? (other.userId != null) : !this.userId.equals(other.userId)) {
return false;
}
return true;
}
}
and it'll work like magic
It seems you are either comparing the wrong (first) object or equals is not correctly implemented as it returns false.
The shown values are just string representations. It doesn't actually mean that both objects have to be equal.
You should check if userDAO.getUser().get(0) actually returns the user you are setting before.
Posting the implementation of User and the userDAO type might help for further clarification.
NOTE: Note directly related to this question but it's answer to my issue that got me to this question. I am sure more ppl might end-up on this post looking for this solution.
This is not precisely the a solution if Equals method needs overriding but something that I very commonly find myself blocked due to:
If you have used Capture and are asserting equality over captured value, please be sure to get the captured value form captured instance.
eg:
Capture<Request> capturedRequest = new Capture<>();
this.testableObj.makeRequest(EasyMock.capture(capturedRequest))
Assert.assertEquals(capturedRequest.getValue(), expectedRequest);
V/S
Assert.assertEquals(capturedRequest, expectedRequest);
while the compiler wont complain in either case, the Assertion Obviously fails in 2nd case

JavaBeans property with if statement

I have a label form JavaFx to disply if an operation was succeed or not. This should updated automaticaly when the value changed
public class operation {
private BooleanProperty success = new SimpleBooleanProperty();
public final boolean getSuccess() {
return success.get();
}
public final void setSuccess(boolean value) {
success.set(value);
}
public BooleanProperty successProperty() {
return success;
}
}
there is somewhere this code:
operation.setSuccess(true);
and this:
label1.textProperty().bind(Bindings.format("%s", operation.successProperty() != null || false? "succeed": "not succeed" ));
The Problem successProperty() is not value and if I invoke getValue() it will not updated on UI
Your condition never changes. operation.successProperty() != null just checks whether the reference returned by the method successProperty() is null: it never is.
I think you want
label1.textProperty().bind(Bindings
.when(operation.successProperty())
.then("succeed")
.otherwise("not succeed"));

Whats the purpose of the last check in Ember.isEmpty function?

function isEmpty(obj) {
return isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && get(obj, 'length') === 0);
}
1) For null and undefined, we have isNone() function
2) For [], '', we have the second check.
3) The purpose of third check?
I believe that is to check for empty objects that have length as an Ember computed property. IE8 and below has no support for Javascript computed properties, so you have to use the Ember syntax to compute them.