不変を暗示するために過去形(受動音声)を使用しますか?(例:Array.TransposedとArray.Transpose)


8

[注:以下は、FxCopルールの引用など、構文と規則が少しC#で重いです。これは私の背景ですが、この説明の意図は言語に依存せず、使用されるコード例は一般に疑似コード。—マイク]

クラスは一般に、オブジェクトインスタンスが実際的な場所では不変であり、クラスメンバーの呼び出し結果にはできる限り副作用がないように設計する必要があることに、私たちは全員同意するでしょう。

ただし、歴史的な命名規則では、「GetSomething」、「DoSomehing」などのアクティブな音声を使用する傾向があり、クラスメンバーが実行するアクションが明確に示されているため、これは適切です。

ただし、メンバーが過去形で名前が付けられると、参照されるオブジェクトに影響を与えることなく値が返されることを暗示することで、時々(または場合によっては)メリットが得られると考え始めています。

たとえば、配列を転置するメソッドの場合、現在の命名スタイルではおそらく 'Array.Transpose'と呼ばれますが、このメンバーが参照されたオブジェクトを転置せずに新しい配列を返す場合、それを 'Array.Transposed'と呼ぶと思います'はより正確になり、プログラマにわかりやすくなります。

'Array.Transpose()'メソッドを使用する場合、誤って次のようなコードを使用しようとする可能性があります。

Array myArray = new Array(); 
myArray.Transpose();

ただし、「Transpose」メソッドが参照オブジェクトに影響を与えずに新しい配列を返す場合、このコードは何もしません。つまり、「myArray」は静かに転置されません。(「転置」がプロパティである場合、コンパイラは上記が正当ではないことをキャッチするでしょうが、FxCopガイドラインでは、変換を実行するメンバーはメソッドである必要があると述べています。)

しかし、メソッドが過去形で 'Array.Transposed'と名付けられている場合、次の構文が必要であることはユーザーには明らかでしょう。

Array myArray = new Array(); 
Array transposedArray = myArray.Transposed();

このカテゴリに当てはまると思う他の名前は、「サイズ変更」対「サイズ変更」、「シフト」対「シフト」などの名前のメンバーです。現在の時制は、参照オブジェクトに影響を与えるメンバーに使用されますが、過去形は、参照されるオブジェクトに影響を与えずに新しい値を返すメンバーに使用されます。

現在より一般的な別のアプローチは、各名前の前に「Get」または「To」を付けることですが、過去形に変更すると意味が効果的に伝わり、不要な重みが追加されると思います。

これはここの他のプログラマにとって意味がありますか、それともこの過去形のアイデアは、それを読むときにあまりにぎこちないように聞こえますか?

編集:

以下の素晴らしい議論、私は皆に感謝します。以下に、あなたのコメントとこれに対する私自身の修正された考え方に基づいて要約したいいくつかのポイントを以下に示します。

「流暢な」構文を連鎖させるメソッド

以下の説明に基づいて、参照されるオブジェクトの内部状態に影響を与えるメンバーまたは影響を与えないメンバーを明確にするために、可変クラスで使用する場合、過去形の使用はおそらく価値があります。

ただし、不変クラスの場合、これはケースの大部分になるはずです(希望するでしょう)、過去形を使用すると、構文が不必要に扱いにくくなる可能性があると思います。

たとえば、メソッドチェーンによって作成されるような「流暢な構文」では、過去形を使用するとコードが読みにくくなります。たとえば、C#を介してLINQを使用する場合、一般的なメソッドチェーンは次のようになります。

dataSource.Sort().Take(10).Select(x => x.ToString);

過去形に変更すると、これは扱いにくくなります。

dataSource.Sorted().Taken(10).Selected(x => x.ToString);

ちなみに、LINQ式は常にソースに影響を与えずに新しい列挙を作成するため、dataSource.Sorted()は実際にはdataSource.Sort()よりも意味が明確です。ただし、このパラダイムを使用するときはこれを十分に認識しているため、過去形の使用は冗長であり、それを読み取る「流暢さ」が本当の意味で不便になります。

プロパティとメソッドの使用

以下で取り上げられた重要な問題は、「取得」メソッドと読み取り専用プロパティの使用に関するFxCopガイドラインに関係しています。例:FxCopルールCA1024

そのFxCopルールでは明示的に言及されていませんが、ToXXXXXX()メソッドは変換メソッドであるため、「To」メソッドの使用はこの根拠にも適用されるようです。また、ToArray()の場合、メソッドは変換メソッドであり、配列を返すメソッドでもあります。

ブールプロパティの過去形の使用

一部の人は、過去形がブール値を暗示する可能性があることを示唆しました。たとえば、「成功」または「接続」プロパティ。ブールのプロパティとフィールドに「Is」、「Has」、または「Are」の使用を強調する以下のレトルトは正しいと思います。過去形もこの点で役立ちますが、「Is」接頭辞を使用する場合ほどではありません。ブール値のプロパティとフィールドに過去形を使用してもかまいませんが、役立ちますが、名前の前に「Is」、「Has」、または「Are」を付けることがさらに重要だと思います。

全体的な結論は?

Tranpose()とTransposed()の問題については、 'skizzy'は適切だと思います。これは、変化するアクションではTranspose()、変化しない結果ではGetTransposed()であることを示唆しています。これにより、100%明確になります。しかし、繰り返しになりますが、これは配列などの変更可能なクラスにのみ当てはまると思います。

不変クラスの場合、特に流暢なメソッドチェーン構文が使用される可能性がある場合、この構文は不必要に扱いにくくなると思います。たとえば、次を比較します。

var v = myObject.Transpose().Resize(3,5).Shift(2);

に:

var v = myObject.GetTransposed().GetResized(3,5).GetShifted(2);

うーん...実際、ここでも、結果がソースに影響を与えないことが100%明確になっているようですが、よくわかりません。

よく知られているLINQのようなパラダイムでは、 "Get"や過去形を使用する必要はありませんが、新しいAPIの場合、最初はある程度の価値があると思います。APIに不変オブジェクトのみが含まれている場合、ユーザーがこれを理解すると、「取得」や過去形の使用は読みやすさだけを低下させます。

簡単な答えはここにはないと思います。API全体について考え、慎重に選択する必要があると思います。

-マイク


メソッド呼び出しの括弧(または、例の言語ではオプションですが、まれですが)を忘れて、これらをプロパティにするつもりはなかったと思います...

こんにちはデルナン、はい、それは財産であり、意図的なものです。プロパティであることにより、 'Transpose'(または 'Transposed')プロパティが値を返し、副作用がないことがさらに明確になります。実際、コンパイラーは上記の誤ったコードの使用法をピックアップする必要がありますが、ここでの考え方は、コンパイラーがピックアップする前に、ユーザーがさらに明確になるようにすることです。
Mike Rosenblum、2011

まったく新しいオブジェクトを作成するときに、すべてにプロパティを使用するのは非常に悪い考えだと思います。それをバックアップするために、MSDNは、「メソッドは時間のかかる操作を実行します。このメソッドは、フィールドの値を設定または取得するのにかかる時間よりも明らかに遅い」と述べた場合、プロパティよりもメソッドが優先されると述べています。

素晴らしい情報源、そのために感謝します。したがって、このメンバーは(a)変換を実行し、(b)配列を返すため、FxCopルールCA1024を超えるため、私の「転置」の例は理想的だったかもしれません。とはいえ、現在時制と過去時制に関する議論は依然として当てはまりますが、変換または配列の結果を返すときは、プロパティではなくToXXXXX()またはGetXXXX()メソッドを使用します。
Mike Rosenblum、

オブジェクトはクラスではなく不変であるべきだと私は思います。クラスは通常、少なくとも静的に型付けされた言語では常に不変です。
Nemanja Trifunovic

回答:


7

ちょっと緊張した感じがします。私はあなたがその単語を形容詞であることを意図していたと思います。

ここにあなたが求めた問題に対する私の提案があります:の代わりにTranspose()と呼んでくださいGetTransposed()。こうすることで、何かを受け取り、オブジェクトを変更していないことがわかります。


1
結局、これは実際には「正しい」答えだと思います。(1)他の人、特に 'qes'と 'Developer Art'が非常に思慮深いコメントをしたため、(2)「正しい」とは思わないので、「正しい」とはマークしません。これに対する答え-これは「コミュニティーWiki」の質問の詳細です。(p.seはそのようなコンセプトを持っていますか?)
マイク・ローゼンブラム

1
+1簡潔な回答です。この方法でTranspose()も、特定のオブジェクトを調整すると解釈できます。おそらくこれは言語の構成要素であるべきです。:) object.Transpose()object:Transpose()
スティーブンジュリス

副作用なしで連続して繰り返される呼び出しが意味的に同一の結果をもたらす場合AsTransposedよりもGetTransposed、私は好みます(同じオブジェクトである場合とそうでない場合がありますがReferenceEquals、同等のものまたは同等のものを使用しないと異なるオブジェクトであるとは示されません)。 。
スーパーキャット2012

6

それは確かに理にかなっています。

私の意見では、あなたが話していることは、APIまたはライブラリを設計するときの一般的なルールとして解釈されるべきです。その場合にのみ、システムがすべてのクラスで一貫していれば、具体的なメリットが得られます。

別の問題は、多くの場合、インターフェースのユーザーは、結果がどのようにして達成されるかについてまったく気にしないということです。

Transpose()は現在のオブジェクトを転置しますか?Transpose()は新しい転置インスタンスを作成し、それへの参照を返しますか?または、おそらく一度転置して、結果をコピーにキャッシュし、現在のオブジェクトに影響を与えることなく、後続の呼び出しでそれを返しますか?

ユーザーはしばしば転置された結果を取得したいだけです。そのため、提案している命名規則を気にする人は多くありません。

しかし、それ自体では、それは有効な提案です。


4

私は強く反対します。過去時制は扱いにくく、一般的には使用されません(それ自体は、それを好まないのに十分な理由です)。

メソッドが呼び出されたオブジェクトを変更した場合、それ自体は返されません。これにより、オブジェクトが変更されたことが明確になります。

同様に、メソッドが呼び出されたオブジェクトを変更せず、代わりに新しいオブジェクトを構築する場合、メソッドは同じタイプのオブジェクトを返します。これは明確ですでに一般的な慣例です。

私の意見では、メソッドシグネチャは、メソッドが新しいオブジェクトを返すか、呼び出し先を変更するかを示すために、より明確で一般的に使用されている規則です。


こんにちは、はい、過去の時制のアプローチは一般的に使用されていないため、ここで質問をしました。(私はそれは理にかなっていると思いますが、前例は多くの意味を持ちます。)メソッドの署名についてのあなたのポイントは良いものですが、残念ながら、コンパイラーは一般にメソッドの結果が使用されることを強制しないため、非常に微妙です。 。そのため、コンパイラーはmyObject.Resize()を呼び出して戻り値を利用しないという間違いを見つけることができませんでした。私の提案では、メソッドの名前を「サイズ変更」にすると、result = myObject.Resized()が必要であることをプログラマーにわかりやすくすることができます。
Mike Rosenblum

1
コンパイラは確実にメソッドの結果が使用されないことを警告することができます。これは、識別子で使用される英語の動詞の時制に基づく動作に対して行うことができる以上のものであり、これは無効な点です。過去形での命名では、次の理由により、それが明確にならないと述べています。1.確立された規則ではない。2.他にも確立された規則があります。3.過去形では非常に扱いにくい、または完全に無効になる単語が多くなりますが、メソッドシグネチャはそのような混乱を招きません。
クエンティンスターリン

確かにコンパイラはこれについて警告することができますが、一般的にはプロパティに対してのみ警告します。使用されないメソッドからの戻り値は、通常、標準設定のほとんどすべてのコンパイラーによって無視されます。
Mike Rosenblum

とはいえ、コメントとFxCopルールCA1024(msdn.microsoft.com/en-us/library/ms182181(VS.80).aspx)について私が考えるほど、私の例は、変換が発生するすべての状況および/または配列が返される場所。その結果、これらはGetXXXXX()またはToXXXXX()メソッドの命名を使用する必要があり、これは正しいと思います。(特に、これは確立された規則であるためです。) "GetTransposed()"のように、渡された時制でメソッドに名前を付けることは、ここでも役に立ちますが、ほんのわずかです。
Mike Rosenblum

3

合理的に聞こえますし、前例があります— Pythonにはとの両方がlist.sort()ありsorted(seq)ます。1つ目はメソッドで、もう1つは反復可能オブジェクトに作用してリストを返す関数です。


list.sort()は何かを返しますか?
クエンティン

いいえ、ありません。
Adam Byrtek、2011

2

Scalaコレクションライブラリには、過去形のメソッドがいくつかあります。

  • grouped戻りのチャンクのシーケンスの要素で反復イテレータn要素
  • sorted コレクションのソートされたバージョンを返します
  • updated 1つの要素が変更されたコレクションの新しいバージョンを返します

ただし、Scalaのコレクションライブラリは非常に豊富であるため、これが意識的な決定なのか、名前が足りなくなったのかはわかりません。たとえば、groupBysortByメソッドもありupdate、コンパイラが割り当てを書き換えるため、メソッドは特別です

foo(bar) = baz

foo.update(bar, baz)

スカラ座の古いバージョンでは、実際にやった使用をupdate不変コレクションのために、しかし持つupdateあなたは明らかに例えば不変のマップ内のエントリはものになるだろう「更新」ので、何かに戻り値を代入する必要があるため、新しいバージョンの復帰を代わりに変異することは、非常に厄介ですお気に入り

val newMap = oldMap(key) = value // HUH ??!!??

さて、

val newMap = oldMap.updated(key -> value)

良い型システムを持つ言語では、型は通常、ルーチンが引数を変更するかどうかを教えてくれます。たとえば、Haskellでは、不変バージョンのタイプは次のようになります。

transpose :: Array -> Array

可変バージョンは次のようになります

transpose :: State Array

1

渡された時制でメソッド/プロパティを見つけたら、すぐにブール値を返すと思います。あなたの提案は論理的に理にかなっているかもしれませんが、それは奇妙でぎこちないようです。なぜそれが理にかなっているのかを誰かに説明しなければならない場合、それはおそらく良い慣例ではありません。


2
そのため、ブール値の前に「is」を付けることは良い規則です。; pさらに、彼がそれを説明する理由は、それが慣習ではないからです。この質問に対するいくつかの回答は、既存の規則に依存しすぎています。慣例がなくても、脇に立ち、それを判断できる必要があります。
スティーブンジュリス

0

私は不変の過去の変数名の大ファンではありません-それはやや珍しい慣習であり、それは特に英語の文法があまり得意ではない人(そして私は半分冗談です)にとって混乱を引き起こすと思いますそこ...)

また、この慣例により、過去形を使用してより重要と思われる何かを表す機会がなくなります。たとえば、「処理されたアイテム」などの説明されたオブジェクトの状態の説明は、コレクション内のアイテムがすでにこれは、伝えるべき重要な論理情報です。

より良いアイデア:すべてを不変にする。次に、特別な言語の区別は必要ありません。自分がしたいって分かってるんでしょ :-)


1
そのため、ブール値の前に「is」と「has」を付けるのは良い慣例です。
Steven Jeuris
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.