true
/true
ではなくfalse
/nothingを返す関数があってもよろしいですか?
私の例ではJavaScriptを使用していますが、特定の言語に関連付けられていない一般的なケースについて疑問に思っています。
私の興味のある主題:
つまり、一部の言語では自由度が高すぎるため、個人的には好きではありません。 C++やJavaのような深刻な言語での動作を追跡する方が良いと思いますが、私はそれらを使用したことはありません。
var a = 1;
var b = 2;
function foo() {
if (a === b)
return true;
}
if (!foo())
alert('error');
versus
function foo() {
if (a === b)
return true;
else
return false;
}
それはあなたが「OK」で何を意味するかによる。
私が精通している言語でそれを行う機能がある場合、null/nil/undefined値は不正です。これは、例で説明されているようにブール演算で使用された場合、false
と同じように解釈されることを意味します。ただし、これがすべての言語にいつでも当てはまるとは限りません。特に、この動作を許可する言語への最初の進出である場合は特に、コードを読んで作業しているすべての人がこれを知っているとは言えません。
個人的には、より明示的なコードを好む。特定の言語の方が多少冗長または慣用性が低い場合でも、読みやすさと保守性が優れていることがよくあります。ただし、何でもそうですが、ソフトウェアを構築するチーム間で決定する必要のあるトレードオフです。多くの場合、このような決定は、リンターやその他の静的分析ツールの構成で体系化でき、開発プロセス中に違反を検出(場合によっては自動修正)できます。
Rubyでは、 nil
とfalse
はfalseyであり、これらは唯一の偽の値 です。他のすべての値はtruthyであり、これにはtrue
(明らかに)が含まれますが、0
、0.0
、""
、[]
など、他の言語が真と見なさない可能性のある値も含まれます、{}
など。
Ruby)にも命名規則があります。その主な目的は、はい/いいえの質問に答えることですが、末尾に疑問符が付きます。
したがって、たとえば Integer#odd?
というメソッドがあります。これは、(おそらく驚くべきことではありませんが)レシーバが奇数の場合はtrue
を返し、レシーバが偶数の場合はfalse
を返します。
1.odd? #=> true
2.odd? #=> false
ただし、ブール値とされるメソッドの戻り値を使用して、一部のextra情報を伝達することは非常に一般的です。実際、最も極端な例はメソッドではなく、組み込み 単項接頭辞defined?
演算子 です。これは、(少なくとも最も広く使用されているRuby実装)実際にブール値を返すことは決してありません!
言語仕様 (セクション11.4.3.2defined?
式)onlyは、defined?
が真を返すことを保証します値またはnil
ですが、偽の値が正確に値false
である必要はありません。そして、多くのRuby実装は、その事実を使用して、プログラマに追加情報を伝えます。たとえば、YARVの場合:
defined? foo #=> nil
def foo; end
defined? foo #=> 'method'
foo = 42
defined? foo #=> 'local-variable'
これは、デバッグの目的で役立つ情報ですが、次のような条件付きコンテキストでdefined?
演算子を使用しても害はありません
def foo; end unless defined? foo
何かの存在を要求するメソッドに対してnil
ではなくfalse
(値の不在を表す値)を返すことは特に一般的です。
一般に、真偽値または偽値として処理する以外に、戻り値を使用して何かを仮定することはできませんが、検査することはできますデバッグ目的のみ。
Rubyコミュニティでは、これは完全に正常であると見なされており、広く使用されているサードパーティライブラリ、標準ライブラリ、およびコアライブラリにこれを行うメソッドがあります。それらのメソッドの仕様は、これを可能にするような方法で明示的に記述されることがよくあります。たとえば、代わりにtruthyまたはfalsey値のみを必要としますtrue
またはfalse
。
true/falseの代わりにtrue/nothingを返す関数があっても大丈夫ですか?
_bool isFoo( int a, int b )
{
if ( a == b ) { return true; }
}
// Evaluated
isFoo(2, 2) // true
isFoo(2, 4) // true
_
isFoo(2, 4)
は未定義の動作です。メモリ内の一部の値がスローされるため、true
を返す可能性が高く、値がある限りtrue
です。
値、戻り値の型から推測する必要があるため、読みにくいです。
_var a = 1; // Must infer that 'a' is an integer
var b = 2;
// must infer from the definition, the boolean
function foo()
{
if (a === b)
return true;
}
if (!foo())
alert('error');
_
コードは書かれている以上に読み込まれます。このため、可能な限り明示する必要があり、あいまいさを残したり、複数の戻り値の型を持つ関数を作成したりしないでください。物事をまっすぐ進み、分離してください。
考慮する必要がある3つの部分があります:意味論的、機械的、および方言。
最も簡単な、メカニックまたは何が機能するかから始めましょう。あなたの言語で何も返せない場合は、falseを返す必要があります。言語でfalseが定義されていない場合は、おそらく何も返さないはずですが、今は方言に移行しています。
コードには、コンピューターに何をすべきかを伝え、次のプログラマーに意図を伝えるための2つの役割があることを覚えておいてください。他のプログラマーとコミュニケーションするとき、各言語がコミュニケーション方法の慣習を発達させていることに気付くでしょう。多くのa JavaプログラマーがJava Cでの規則を逆に使用することで非難されました。そのため、明示的に何かを通信する特定の必要がない限り、以下に従ってください。あなたの言語の慣習。
ただし、明示的なことを言いたい場合もあります。これが最も困難で微妙なポイントが発生する場所です。コードの意味上の意味は何ですか。応答がない場合と、問題があるかどうかを尋ねられた場合の「いいえ」の意味はまったく異なり、それぞれの答えは特定の状況に適しています。
だから、あなたが何を言おうとしているのかを考え、それを言ってください。
これについて一般的に質問しているので、型付き言語がこれから何を作るかを検討する価値があります。
多くの人がそれを処理できます。たとえば、TypeScriptでは次のように記述します。
function foo(a: any, b: any): boolean | void {
if (a === b)
return true;
}
しかし、C#では、何を返しますか?次のコードは、すべてのコードパスが値を返すわけではないため、コンパイルされません。
public static bool Foo(String a, String b) {
if (a == b) {
return true;
}
}
しかし、代わりにエラーをスローすることができます:
public static bool Foo(int a, int b) {
if (a == b) {
return true;
} else {
throw new Exception();
}
}
したがって、少なくとも一部の言語では、関数から返される値は一貫した型である必要があります。そうでない場合、関数はエラーをスローする必要があります。
他のパラダイム、たとえば関数型プログラミングでは、値を返さないことは厳密にルールに反しますが、多分返すかもしれませんが、次のHaskellコードを検討してください。
g :: Int -> Int -> Maybe Bool
g x y
| x == y = Just True
| otherwise = Nothing
それは確かに非常に奇妙です。
結局のところ、これは好みの問題ですが、boolean
型はboolean | undefined
またはMaybe Bool
よりも複雑ではないと言えると思います。
(Oracle)SQLストアド関数を見てみましょう:
CREATE FUNCTION isEqual(
a IN NUMBER,
b IN NUMBER
) RETURN BOOLEAN DETERMINISTIC
IS
BEGIN
IF a = b THEN
RETURN a = b;
ELSE
RETURN NULL;
END IF;
END;
/
次に、それを呼び出してみます。
DECLARE
value BOOLEAN := isEqual( 1, 2 );
BEGIN
IF value THEN
DBMS_OUTPUT.PUT_LINE( 'Equal' );
ELSIF NOT value THEN
DBMS_OUTPUT.PUT_LINE( 'Not Equal' );
ELSE
DBMS_OUTPUT.PUT_LINE( 'Neither Equal nor Not Equal' );
END IF;
END;
/
出力は何だと思いますか?
それは:
Neither Equal nor Not Equal
db <> fiddle ここ
一部の言語ではFALSE
と不明なNULL
/nil
/undefined
に違いがあり、BOOLEAN
値には、TRUE
、FALSE
またはNULL
(未定義)の3つの状態があり、値がfalseであるか、未定義であるかと、あなたはそれがtrueかfalseのどちらであるかわかりません。
プログラミングは、コンピュータにあなたがやりたいことをさせるだけではないことを忘れないでください。また、コンピューターの動作をコードの読者に説明します。一部のコードパスで値を返し、他のパスでは返さないのは混乱を招きます。将来の読者にとっては見落としのように見えるかもしれません。
別のメモでは、次のようなコードパターン
if (condition) {
return true
} else {
return false
}
通常は次のように書き換える必要があります
return condition
nothing
を返すのではなく、something
を返す必要があると思います。
私が意味したことは、プログラミング言語とは関係なく、function/method
の名前が内部で何を行うかを定義することです。読みやすさのためですよね? function/method
の名前は、誰かが初めてそれを見たときにヒントを与えます。誰かがそれが何をするのか知りたいのなら、彼はきっと全体の定義を通過しなければなりませんが、名前は最初にいくつかの要約を与えるべきです。
この事実を考慮して、function/method
から何かを常に期待していますか? function/method
の名前はそれが何をするかを教えてくれ、私たちは知っています、「わかりました、これはfunction/method
からこれを期待しています」
だからあなたの例から、
function foo() {
if (a === b)
return true;
else
return false;
}
私たちが観察しているのは、2つの変数が値と型の両方で等しいかどうかをチェックすることを定義が示していることです。それで私たちは何を期待しますか?
誰かare these two things equal?
に尋ねると、Yes! They are equal
またはNo! They are not equal
のどちらかが期待されます。 True
またはFalse
を意味します。
したがって、チームメンバーがコードを読んでいるときも、同じことが期待されます。ただし、nothing
を返すと、期待と一致しません。
nothing
を返すと、ほとんどanything
を返すことができますか?したがって、関数がTrue
のanything
を返すことを期待している場合、それをif
条件内に置くと、常にTrue
とif
ブロックは常に実行されます。 [返される場合None, nill, null, 0
]
したがって、呼び出し元の関数は非常に多くのシナリオを処理する必要があります。 float value/string value/integer value/etc...
を取得していますか
だからそれは私が言う不必要なチェックです!
something
を返すのが良いと思うのはそのためです。
あなたの場合、nothing
よりtrue/false
を返します。
また、ヒントとして、if-else
ブロックを記述するのではなく、コードを1行ずつ少しずつ整理できます。
function foo() {
return a === b;
}
大丈夫ですか?
それは機能するという意味で?
はい
言語によって異なります。 Javaたとえば、「ブール値」を返すメソッドがあるとしますが、実際にはtrueまたはnullのいずれかのみを返し、falseは返しません。
それは意味がありますか?
可能ですが、ほとんどの場合、設計が不適切であることを示しています。
これは、何かが真実であることがわかっている場合、または何かの状態がわからない場合を表しています。つまり、ドローンをランダムな惑星にテレポートさせたとしましょう。太陽を見れば、その太陽系に太陽が存在していることがわかります。太陽が見えなければ、わかりません。現在、太陽が見えていないだけかもしれません。したがって、メソッド「isThereASun」は、意味的に「true」またはnullでのみ応答するのが正しい場合があります。ただし、ソフトウェア設計の観点からは、不必要に複雑に思われます。コード呼び出しでは、「false」は決して当てはまらないため、nullとfalseを別々のケースとして扱う必要があります。おそらく両方の場合に適用するロジックは同じです。現時点ではソーラーパネルを消さないでください。ドキュメントでfalseは決して発生しないことを明確にすることができますが、これは危険です(そして、戻り値の宣言を使用して可能な回答を明示的にするという言語の理想に反します)-誰かがメソッドを変更した場合、その部分を変更する必要がありますドキュメントと、それを呼び出すすべてのメソッドがケースをカバーすることを確認してください。この追加の負担を回避し、関数の動作を最初から明確にするには、単純に「doWeSeeASun」または「areSunRaysAvailable」に名前を変更します。次に、答えは常にtrueまたはfalseである必要があり、呼び出しコードはnull値について心配する必要はありません。 (言語によっては対処する必要があるかもしれませんが、null値は、他の予期しない動作と同様に、より高いレベルで対処できる予期しない動作を示します)。
別の有効なアプローチ
独自の応答タイプ、たとえば値が「TRUE」と「NO IDEA」の列挙型を考え出すこともできます。これにより、回答が2進であるが、真または偽ではない場合の応答が明確に定義されます。