JavaScriptでは様々な値が真偽値として特徴的な振る舞いを見せます。
falseとして振る舞う値
- undefined
- null
- false
- -0, 0, NaN
- ""
trueとして振る舞う値
- true
- -0, 0, NaN以外のnumber
- ""以外のstring
- その他のオブジェクト
これらはif文で活用することで読みやすくも読みにくくもなる面白いテクニックですが、同様のことをDartでも検証してみました。
undefined
Dartにはそもそもundefinedという値はありません。また、未定義のシンボルを呼びだそうとすると実行時エラーとなりますので、undefinedについては真偽値が得られません。
/// NoSuchMethodError: method not found 'get:obj'
test("undefined", () {
if (obj) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
面白いのは、obj
という名前の変数がないとき、obj
のgetterがないというエラーになることですね。
null
nullに関してはJavaScriptと同様の振る舞いを見せました。これは直感的なので違和感もないですね。
/// Passed : null => false
test("null", () {
var obj;
if (obj) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
number
numberはすべての場合においてfalseとして振る舞いました。
group("number", () {
/// Passed : 0 => false
test("0", () {
if (0) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Passed : -0 => false
test("-0", () {
if (-0) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : -1 => false
test("-1", () {
if (-1) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
/// Failed : 1 => false
test("1", () {
if (1) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
/// Passed : NaN => false
test("NaN", () {
if (double.NAN) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
});
string
stringにおいても、すべての場合でfalseとして振る舞いました。
group("string", () {
/// Passed : "" => false
test("empty", () {
if ("") {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : "true" => false
test("true string", () {
if ("true") {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
});
その他のオブジェクト
その他のオブジェクトに関してもすべてfalseの振る舞いになりました。
group("object", () {
/// Passed : {} => false
test("empty object", () {
if ({
}) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : object => false
test("not empty object", () {
if ({
"name" : "laco",
"flag" : false
}) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
});
まとめ
Dartでtrueとして振る舞う値
- true
Dartでfalseとして振る舞う値
- その他すべて
ということになりました。さすが型安全というべきでしょう。感動しました。今回の調査に使ったソースコードを最後に添付しておきます。実行は$ dart object_as_bool_test.dart
です。
ちなみに、dartの実行時に$ dart --checked object_as_bool_test.dart
とすると、boolean以外を真偽値として扱おうとしている事自体がエラーとなってテストがすべてエラー落ちします。use struct
みたいなものですね。
object_as_bool_test.dart
import 'package:unittest/unittest.dart';
main() {
/// NoSuchMethodError: method not found 'get:obj'
test("undefined", () {
if (obj) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Passed : null => false
test("null", () {
var obj;
if (obj) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
group("number", () {
/// Passed : 0 => false
test("0", () {
if (0) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Passed : -0 => false
test("-0", () {
if (-0) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : -1 => false
test("-1", () {
if (-1) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
/// Failed : 1 => false
test("1", () {
if (1) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
/// Passed : NaN => false
test("NaN", () {
if (double.NAN) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
});
group("string", () {
/// Passed : "" => false
test("empty", () {
if ("") {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : "true" => false
test("true string", () {
if ("true") {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
});
group("object", () {
/// Passed : {} => false
test("empty object", () {
if ({
}) {
expect(true, isFalse);
} else {
expect(false, isFalse);
}
});
/// Failed : object => false
test("not empty object", () {
if ({
"name" : "laco",
"flag" : false
}) {
expect(true, isTrue);
} else {
expect(false, isTrue);
}
});
});
}