動的に型付けされた言語の単一の関数から異なるデータ型を返すのは悪い考えですか?


65

私の第一言語は静的に型付けされています(Java)。Javaでは、すべてのメソッドから単一の型を返す必要があります。たとえば、条件付きでを返すメソッドStringや、条件付きでを返すメソッドを持つことはできませんInteger。しかし、たとえばJavaScriptでは、これは非常に可能です。

静的に型付けされた言語では、これが悪い考えである理由がわかります。すべてのメソッドが返された場合Object(すべてのクラスが継承する共通の親)、あなたとコンパイラはあなたが何を扱っているのか分かりません。実行時にすべての間違いを発見する必要があります。

しかし、動的に型付けされた言語では、コンパイラーさえ存在しない場合があります。動的に型付けされた言語では、複数の型を返す関数が悪い考えである理由は私には明らかではありません。静的言語の私のバックグラウンドにより、このような関数を書くことは避けられますが、コードを見えないようにすっきりさせることができる機能については気にされているのではないかと心配しています。


編集:私の例を削除します(より良い例を考えることができるまで)。私がやろうとしているのではない点に返信するように人々を誘導していると思います。


エラーの場合に例外をスローしないのはなぜですか?
TrueWill

1
@TrueWillは次の文で対処します。
ダニエルカプラン

これは、より動的な言語の一般的な慣行であることに気づきましたか?関数型言語では一般的ですが、ルールは非常に明確にされています。そして、特にJavaScriptでは、引数を異なる型にすることが一般的であることを知っています(これが本質的に関数のオーバーロードを行う唯一の方法であるため)が、これが戻り値に適用されることはほとんどありません。私が考えることができる唯一の例は、ほとんど自動化された配列ラッピング/アンラッピングを備えたPowerShellであり、スクリプト言語は例外的なケースです。
アーロンノート14年

3
言及されていませんが、戻り値の型をパラメーターとしてとる関数の多くの例があります(Javaジェネリックでも)。たとえば、Common Lispでは(coerce var 'string)、a stringまたは(concatenate 'string this that the-other-thing)同様の利回りがあります。私ThingLoader.getThingById (Class<extends FindableThing> klass, long id)も同様のことを書きました。そして、そこに、私はあなたが尋ねサブクラス何かを返すことがあります:loader.getThingById (SubclassA.class, 14)返される可能性がありますSubclassBそれが伸びをSubclassA...
BRPocock

1
動的に型付けされた言語は、映画「マトリックススプーンのようなものです。スプーン文字列または数値として定義しようとしないでください。それは不可能でしょう。代わりに...真実を理解しようとするだけです。スプーンがないこと。
Reactgular 14年

回答:


42

他の答えとは対照的に、異なる型を返すことが許容される場合があります。

例1

sum(2, 3)  int
sum(2.1, 3.7)  float

一部の静的型付け言語では、これはオーバーロードを伴うため、それぞれが事前定義された固定型を返す複数のメソッドがあると考えることができます。動的言語では、これは同じ機能であり、次のように実装されます。

var sum = function (a, b) {
    return a + b;
};

同じ関数、異なるタイプの戻り値。

例2

OpenID / OAuthコンポーネントから応答を受け取ると想像してください。一部のOpenID / OAuthプロバイダーには、個人の年齢など、より多くの情報が含まれる場合があります。

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Facebook',
//     name: {
//         firstName: 'Hello',
//         secondName: 'World',
//     },
//     email: 'hello.world@example.com',
//     age: 27
// }

他の人は最小限のものを持っているでしょう、それは電子メールアドレスか仮名でしょうか。

var user = authProvider.findCurrent();
// user is now:
// {
//     provider: 'Google',
//     email: 'hello.world@example.com'
// }

繰り返しますが、同じ機能、異なる結果です。

ここで、異なる型を返すことの利点は、型とインターフェイスについては気にしないが、実際にはどのオブジェクトが含まれているかというコンテキストでは特に重要です。たとえば、ウェブサイトに成熟した言語が含まれているとします。次に、findCurrent()このように使用できます:

var user = authProvider.findCurrent();
if (user.age || 0 >= 16) {
    // The person can stand mature language.
    allowShowingContent();
} else if (user.age) {
    // OpenID/OAuth gave the age, but the person appears too young to see the content.
    showParentalAdvisoryRequestedMessage();
} else {
    // OpenID/OAuth won't tell the age of the person. Ask the user himself.
    askForAge();
}

これをコードにリファクタリングすると、すべてのプロバイダーが、明確に定義された固定型を返す独自の機能を持つようになり、コードベースが低下し、コードの重複が発生するだけでなく、メリットもありません。次のような恐怖をすることになります。

var age;
if (['Facebook', 'Yahoo', 'Blogger', 'LiveJournal'].contains(user.provider)) {
    age = user.age;
}

5
「静的に型付けされた言語では、これはオーバーロードを伴い ます」あなたは「いくつかの静的に型付けされた言語で」を意味すると思います:)良い静的に型付けされた言語は、あなたのsum例のようなものにオーバーロードを必要としません。
アンドレス

17
具体的な例として、Haskell:を検討してくださいsum :: Num a => [a] -> a。数値のリストを合計できます。javascriptとは異なり、数値ではないものを合計しようとすると、コンパイル時にエラーが捕捉されます。
アンドレス

3
@MainMa Scalaでは、Iterator[A]method def sum[B >: A](implicit num: Numeric[B]): Bがあります。このメソッドでも、あらゆる種類の数値を合計でき、コンパイル時にチェックされます。
ペトルスキー-パドラック

3
@Bakuriuもちろん、このような関数を書くこともできますが、最初+に文字列をオーバーロードする必要があります(を実装することでNum、デザイン的には合法ですが、整数と文字列でオーバーロードされる別の演算子/関数を発明する必要があります)それぞれ。Haskellには、型クラスを介したアドホックなポリモーフィズムがあります。整数と文字列の両方を含むリストははるかに難しく(おそらく言語拡張なしでは不可能)、かなり異なる問題です。

2
2番目の例には特に感心していません。これらの2つのオブジェクトは同じ概念的な「タイプ」であり、特定のフィールドが定義または設定されていない場合もあります。null値を持つ静的に型付けされた言語であっても、それをうまく表現できます。
アーロンノート14

31

一般に、静的に型付けされた言語の道徳的な同等物が悪い考えであるのと同じ理由で悪い考えです:どの具体的な型が返されるのかわからないので、結果で何ができるかわかりません(任意の値で実行できることはほとんどありません)。静的型システムでは、戻り値の型などのコンパイラーチェックアノテーションがありますが、動的言語でも同じ知識が存在します。ソースコードではなく、脳とドキュメントに非公式で保存されています。

ただし、多くの場合、型が返される韻と理由があり、その効果は静的型システムのオーバーロードまたはパラメトリック多型に似ています。言い換えれば、結果の型予測可能であり、表現するのはそれほど単純ではありません。

しかし、特定の関数が不適切に設計されている他の理由があるかもしれないことに注意してください:たとえば、sum無効な入力でfalseを返す関数は、主にその戻り値が役に立たずエラーが発生しやすい(0 <-> false混乱)ため、悪い考えです。


40
私の2セント:それが起こるとき、私はそれを嫌います。結果がない場合、1つの結果にオブジェクトがあり、2つ以上の結果に配列がある場合にnullを返すJSライブラリを見てきました。したがって、単に配列をループするのではなく、nullであるかどうか、nullでない場合は配列であるかどうかを判断する必要があります。特に、通常の意味で、正気な開発者はオブジェクトを配列に追加し、プログラムロジックをリサイクルして配列を処理するだけです。
phyrfox 14年

10
@Iskata:NaN「カウンターポイント」とはまったく思いません。NaNは、実際には浮動小数点計算の有効な入力です。NaN実際の番号でできることなら何でもできます。確かに、上記の計算の最終結果はあまり役に立たないかもしれませんが、奇妙な実行時エラーにつながることはなく、常にチェックする必要はありません-最後に一度だけチェックすることができます一連の計算。NaNは別のではなく、単なる特別なであり、Null Objectのようなものです。
アーロンノート14年

5
一方、@ Aaronaught NaNは、nullオブジェクトのように、エラーが発生したときに非表示になる傾向があり、後でエラーがポップアップするだけです。たとえばNaN、ループ条件に陥ると、プログラムが爆発する可能性があります。
イズカタ14年

2
@Izkata:NaNとnullの動作はまったく異なります。null参照はアクセスするとすぐに爆発し、NaNが伝播します。後者が発生する理由は明らかであり、すべての部分式の結果を確認することなく数式を書くことができます。NaNは適切な数値概念を表しているので、個人的にはnullがはるかに有害であると考えています。NaNは逃げることができず、数学的には伝播が正しい動作です。
Phoshi

4
これが「null vs. else」引数に変わった理由はわかりません。私は単にことが指摘されたNaN値は、(a)は、実際には異なる戻り型及び(b)は、明確に定義された浮動小数点のセマンティクスを有していないので、実際に可変型付けされた戻り値のアナログとして適格でありません。実際、整数演算のゼロとそれほど違いはありません。ゼロが誤って計算にスリップすると、多くの場合、結果としてゼロまたはゼロ除算エラーが発生する可能性が高くなります。IEEE浮動小数点で定義された「無限」値も悪ですか?
アーロンノート14年

26

動的言語では、異なる型ではなく、異なるAPIを持つオブジェクトを返すかどうかを尋ねるべきではありません。ほとんどの動的言語は実際には型を気にせず、さまざまなバージョンのダックタイピングを使用します

異なる型を返すときは意味があります

たとえば、このメソッドは理にかなっています:

def load_file(file): 
    if something: 
       return ['a ', 'list', 'of', 'strings'] 
    return open(file, 'r')

ファイルと文字列のリストの両方が(Pythonでは)文字列を返す反復可能オブジェクトであるためです。非常に異なるタイプ、同じAPI(誰かがリストのファイルメソッドを呼び出そうとしない限り、これは別の話です)。

条件付きで返すことができます(listまたはPythonの不変リストです)。tupletuple

正式に行うこと:

def do_something():
    if ...: 
        return None
    return something_else

または:

function do_something(){
   if (...) return null; 
   return sth;
}

Python NoneとJavascriptの両方nullが独自のタイプであるため、異なるタイプを返します。

これらのユースケースはすべて静的言語で対応するものがあり、関数は適切なインターフェイスを返すだけです。

条件に応じて異なるAPIを持つオブジェクトを返すことをお勧めします

異なるAPIを返すことが良いアイデアかどうかについては、ほとんどの場合、IMOは意味をなしません。頭に浮かぶ賢明な例は、@ MainMaが言ったことに近いものです。APIがさまざまな量の詳細を提供できる場合、利用可能な場合により多くの詳細を返すことが理にかなっています。


4
いい答えだ。Java /静的に型付けされた同等物は、API /抽象化を表すインターフェースを使用して、特定の具象型ではなくインターフェースを関数が返すようにすることです。
ミケラ14年

1
Pythonでは、リストとタプルは異なる「タイプ」である可能性がありますが、それらは同じ「アヒルタイプ」である、つまり同じ操作セットをサポートしていると思います。そして、このようなケースはまさにカモタイピングが導入された理由です。Javaでもlong x = getInt()を実行できます。
ケルバー14年

「異なる型を返す」とは、「異なるAPIを持つオブジェクトを返す」ことを意味します。(一部の言語は、オブジェクトの構築方法をAPIの基本的な部分にしますが、そうでないものもあります。これは、型システムの表現力の問題です。)リスト/ファイルの例でdo_fileは、どちらの方法でも反復可能な文字列を返します。
ジル「SO-悪であるのをやめる」14年

1
そのPythonの例でiter()は、リストとファイルの両方を呼び出して、両方の場合で結果が反復子としてのみ使用できるようにすることもできます。
RemcoGerlich

1
戻ることNone or somethingは、PyPy、Numba、Pystonなどのツールによって実行されるパフォーマンス最適化のキラーです。これは、Pythonをそれほど速くしないPython主義の1つです。
マット14

9

あなたの質問は私が少し泣きたいです。あなたが提供した使用例ではなく、誰かがこのアプローチを無意識のうちに行き過ぎてしまうためです。それはばかげて保守できないコードから少し離れています。

エラー条件のユースケースの種類は理にかなっており、静的に型付けされた言語のnullパターン(すべてがパターンでなければなりません)は同じタイプのことを行います。関数呼び出しはを返すobjectか、を返しますnull

ただし、「これを使用してファクトリパターンを作成する」と言って、関数のムードに応じて、fooまたはbarその両方を返すのは簡単ですbaz。これをデバッグすることは、呼び出し側が期待しfooているが与えられたときに悪夢になりbarます。

だから、あなたが心を閉ざしているとは思わない。あなたは言語の機能をどのように使用するかについて適切に注意しています。

開示:私の背景は静的に型付けされた言語であり、一般に、保守可能なコードの必要性がかなり高い、より大きく多様なチームで働いてきました。したがって、私の見方もおそらく歪んでいます。


6

Javaでジェネリックを使用すると、静的な型の安全性を維持しながら、異なる型を返すことができます。関数呼び出しのジェネリック型パラメーターで返す型を指定するだけです。

Javascriptで同様のアプローチを使用できるかどうかは、もちろん未解決の問題です。Javascriptは動的に型付けされた言語であるため、返さobjectれるのは当然の選択のようです。

静的に型付けされた言語での作業に慣れているときに、動的な戻りシナリオがどこで機能するかを知りたい場合はdynamic、C#でキーワードを調べることを検討してください。Rob Coneryは、キーワードを使用して、400行のコードでオブジェクトリレーショナルマッパーを正常に記述できましたdynamic

もちろん、実行時の型の安全性を備えdynamicobject変数をラップするだけです。


4

異なる型を条件付きで返すのは悪い考えだと思います。これが私にとって頻繁に出てくる方法の1つは、関数が1つ以上の値を返すことができるかどうかです。値を1つだけ返す必要がある場合、呼び出し関数で値をアンパックする必要を避けるために、値を配列にパックするのではなく、単に値を返すのが妥当と思われる場合があります。ただし、これ(およびこの他のほとんどのインスタンス)は、両方のタイプを区別して処理するために呼び出し元に義務を課します。この関数は、常に同じ型を返すかどうかを簡単に判断できます。


4

「悪い習慣」は、言語が静的に入力されているかどうかに関係なく存在します。静的言語はこれらの慣行からあなたを遠ざけてくれるので、静的言語はより正式な言語であるため、「悪い慣行」について不満を言うユーザーをより多く見つけるかもしれません。ただし、根本的な問題は動的言語に存在するため、それらが正当化されるかどうかを判断できます。

ここにあなたが提案するものの好ましくない部分があります。返される型がわからない場合、すぐに戻り値を使用することはできません。私はそれについて何かを「発見」しなければなりません。

total = sum_of_array([20, 30, 'q', 50])
if (type_of(total) == Boolean) {
  display_error(...)
} else {
  record_number(total)
}

多くの場合、この種のコードの切り替えは単に悪い習慣です。コードが読みにくくなります。この例では、例外のスローとキャッチが一般的な理由がわかります。別の言い方をすれば、関数が言っていることを実行できない場合、関数は正常に戻りません。あなたの関数を呼び出す場合、これを行いたい:

total = sum_of_array([20, 30, 'q', 50])
display_number(total)

最初の行が正常に返されるため、total実際には配列の合計が含まれていると想定します。正常に戻らない場合は、プログラムの他のページにジャンプします。

エラーの伝播だけではない別の例を使用してみましょう。たぶんsum_of_arrayはスマートになり、「それは私のロッカーの組み合わせです!」配列が[11,7,19]の場合のみ。良い例を考えるのに苦労しています。とにかく、同じ問題が適用されます。何かをする前に、戻り値を調べる必要があります。

total = sum_of_array([20, 30, 40, 50])
if (type_of(total) == String) {
  write_message(total)
} else {
  record_number(total)
}

関数が整数または浮動小数点数を返すことが有用であると主張するかもしれません。例えば:

sum_of_array(20, 30, 40) -> int
sum_of_array(23.45, 45.67, 67.789044) -> float

しかし、あなたが懸念している限り、これらの結果は異なるタイプではありません。あなたはそれらを数字として扱います、そしてそれはあなたが気にするすべてです。したがって、sum_of_arrayは数値型を返します。これがポリモーフィズムです。

そのため、関数が複数の型を返すことができる場合、違反している可能性のある慣行があります。それらを知ることは、特定の関数がとにかく複数の型を返す必要があるかどうかを判断するのに役立ちます。


申し訳ありませんが、私はあなたを私の悪い例で迷わせました。そもそも言及したことは忘れてください。最初の段落がポイントです。私もあなたの2番目の例が好きです。
ダニエルカプラン14年

4

実際、静的に型付けされた言語であっても、異なる型を返すことはまったく珍しいことではありません。そのため、たとえばユニオン型があります。

実際、Javaのメソッドは、ほとんど常に4つのタイプのいずれかを返します。ある種のオブジェクト、nullまたは例外、またはまったく戻りません。

多くの言語では、エラー条件は、結果タイプまたはエラータイプのいずれかを返すサブルーチンとしてモデル化されます。たとえば、Scalaの場合:

def transferMoney(amount: Decimal): Either[String, Decimal]

もちろんこれは愚かな例です。戻り型は、「文字列または小数を返す」ことを意味します。慣例により、左のタイプはエラータイプ(この場合、エラーメッセージを含む文字列)で、右のタイプは結果のタイプです。

これは例外と似ていますが、例外も制御フローの構成要素であるという事実を除きます。実際、それらは表現力においてに相当しますGOTO


例外を返すJavaのメソッドは奇妙に聞こえます。「戻る例外をうーん...」
ブヨ

3
例外は、Javaのメソッドの結果の1つです。実際、4番目のタイプを忘れていましたUnit(メソッドはまったく返す必要はありません)。確かに、実際にはreturnキーワードを使用しませんが、それでもメソッドから返される結果です。チェック例外を使用すると、タイプシグネチャでも明示的に言及されます。
ヨルグWミットタグ14年

そうですか。あなたのポイントはいくつかのメリットを持っているように見えるが、それは提示の道は、それが魅力的な...むしろ反対に見えるようにしない
ブヨ

4
多くの言語では、エラー条件は、結果タイプまたはエラータイプのいずれかを返すサブルーチンとしてモデル化されます。例外も同様の考え方です。ただし、例外は制御フローの構造体でもあります(GOTO実際には、表現力が等しい)。
ヨルグWミットタグ14年

4

固体の原則についてはまだ答えがありません。特に、期待される型以外の型を受け取るクラスは、返される型をテストするために何もすることなく、取得したもので動作できるという、リスコフ置換の原則に従う必要があります。

したがって、オブジェクトに追加のプロパティをスローするか、元の関数が目的としていたことを達成する何らかのデコレータで返された関数をラップする場合、関数を呼び出すコードがこれに依存しない限り、あなたは良いですすべてのコードパスでの動作。

文字列または整数を返す代わりに、スプリンクラーシステムまたは猫を返すより良い例があります。これは、呼び出し元のコードがすべてfunctionInQuestion.hiss()を呼び出すだけの場合に問題ありません。実際には、呼び出し元のコードが予期している暗黙的なインターフェイスがあり、動的に型付けされた言語はインターフェイスを明示的にすることを強制しません。

悲しいことに、同僚はおそらくそうするので、ドキュメントでとにかく同じ作業をする必要があります。ただし、インターフェイスを定義するときのように、普遍的に受け入れられ、簡潔で、機械分析可能な方法はありません。それらを持っている言語で。


3

私がさまざまなタイプを送信しているのは、無効な入力や、「例外的な」条件がそれほど例外的ではない「貧しい人の例外」の場合です。たとえば、PHPユーティリティ関数の私のリポジトリから、この簡単な例を示します。

function ensure_fields($consideration)
{
        $args = func_get_args();
        foreach ( $args as $a ) {
                if ( !is_string($a) ) {
                        return NULL;
                }
                if ( !isset($consideration[$a]) || $consideration[$a]=='' ) {
                        return FALSE;
                }
        }

        return TRUE;
}

この関数は名目上BOOLEANを返しますが、無効な入力ではNULLを返します。PHP 5.3以降、すべての内部PHP関数も同様に動作することに注意しください。さらに、一部の内部PHP関数は、公称入力でFALSEまたはINTを返します。以下を参照してください。

strpos('Hello', 'e');  // Returns INT(1)
strpos('Hello', 'q');  // Returns BOOL(FALSE)

4
そして、これがPHPが嫌いな理由です。とにかく、理由の1つです。
アーロンノート14年

1
誰かが私がプロとして開発した言語を好まないからです!?私がユダヤ人だとわかるまで待ってください!:)
dotancohen

3
コメントする人と投票する人が同じ人であると常に想定しないでください。
アーロンノート14年

1
私は例外を持っている代わりにすることを好むnull(a)は、それはので、大声で失敗したので、開発/テストの段階に固定される可能性が高いですが、私は一度、すべてのレア/予期しない例外をキャッチすることができますので、(B)は、取り扱いが容易ですアプリケーション全体(フロントコントローラー内)をログに記録するだけです(通常、開発チームにメールを送信します)。後で修正できます。そして、標準のPHPライブラリはほとんど「nullを返す」アプローチを使用していることを嫌いますisset()
Scriptin 14年

1
また、nullエラーで戻った場合は、docblock(例@return boolean|null)でそれを明確にしてください。そうすれば、いつかコードに出くわしても、関数/メソッドの本体を確認する必要はありません。
scriptin 14年

3

これは悪い考えではないと思います!この最も一般的な意見とは対照的で、ロバート・ハーベイが既に指摘したように、Javaのような静的型付け言語は、まさにあなたが求めているような状況のためにジェネリックを導入しました。実際、Javaはコンパイル時に(可能な限り)タイプセーフを維持しようとしますが、ジェネリックはコードの重複を避けることがあります。なぜですか?異なる型を処理/返す同じメソッドまたは同じクラスを記述できるためです。このアイデアを示すために、非常に簡単な例を示します。

Java 1.4

public static Boolean getBoolean(String property){
    return (Boolean) properties.getProperty(property);
}
public static Integer getInt(String property){
    return (Integer) properties.getProperty(property);
}

Java 1.5+

public static <T> getValue(String property, Class<T> clazz) throws WhateverCheckedException{
    return clazz.getConstructor(String.class).newInstance(properties.getProperty(property));
}
//the call will be
Boolean b = getValue("useProxy",Boolean.class);
Integer b = getValue("proxyPort",Integer.class);

動的型付き言語では、コンパイル時に型安全性がないため、多くの型で機能する同じコードを自由に記述できます。静的に型付けされた言語でもジェネリックがこの問題を解決するために導入されたので、動的な言語で異なる型を返す関数を書くことは悪い考えではないことは明らかにヒントです。


説明のない別のダウン投票!SEコミュニティに感謝します!
thermz

2
同情+1する。より明確で直接的な回答で回答を開いてみて、さまざまな回答にコメントすることは控えてください。(私はあなたに同意するので、あなたにもう1つを与えますが、私は1つだけを与えます。)
DougM 14年

3
ジェネリックは動的に型付けされた言語(私が知っている)には存在しません。彼らがする理由はないでしょう。ほとんどのジェネリックは特別なケースであり、「コンテナ」はその中にあるものよりも興味深いものです(これが、Javaなどの一部の言語が実際に型消去を使用する理由です)。ジェネリック型は、実際には独自の型です。ここの例のように、実際のジェネリック型を持たないジェネリックメソッドは、ほとんどの場合、割り当てとキャストのセマンティクスの単なるシュガーです。質問が本当に尋ねているものの特に説得力のある例ではありません。
アーロンノート14年

1
私はもう少しシンセティックになろうとしています:「静的に型付けされた言語でもジェネリックがこの問題を解決するために導入されたので、動的言語で異なる型を返す関数を書くことは悪い考えではないことは明らかです。」今はまし?ロバート・ハーヴェイの答えやBRPocockのコメントをチェックして、あなたは、ジェネリック医薬品の例は、この問題に関連していることを実現します
thermz

1
気分を悪くしないでください、@ thermz。Downvotesは、多くの場合、作家よりも読者についてもっと言います。
カールビーレフェルト14年

2

ソフトウェアの開発は、基本的には複雑さを管理するための芸術であり技術です。余裕のあるポイントでシステムを絞り込み、他のポイントでオプションを制限しようとします。関数のインターフェイスはコントラクトであり、任意のコードを操作するために必要な知識を制限することにより、コードの複雑さを管理するのに役立ちます。さまざまなタイプを返すことにより、返されるさまざまなタイプのすべてのインターフェースを追加し、返されるインターフェースに関する明白でないルールを追加することにより、関数のインターフェースを大幅に拡張します。


1

関数が行うことはそのコンテキストに依存するため、Perlはこれを頻繁に使用します。たとえば、関数は、リストコンテキストで使用される場合は配列を返し、スカラー値が期待される場所で使用される場合は配列の長さを返すことができます。「perl context」の最初のヒットであるチュートリアルから:

my @now = localtime();

@nowは配列変数(@の意味)であり、(40、51、20、9、0、109、5、8、0)のような配列が含まれます。

代わりに、結果をスカラーにする必要がある方法で関数を呼び出す場合、($変数はスカラーです):

my $now = localtime();

その後、まったく異なることを行います。$ nowは、「2009年1月9日金曜日20:51:40」のようになります。

私が考えることができるもう1つの例は、REST APIの実装です。ここでは、返される形式がクライアントの要求に依存します。たとえば、HTML、またはJSON、またはXML。技術的にはこれらはすべてバイトのストリームですが、考え方は似ています。


-あなたはそれがperlでこれを行い、特定の方法に言及する場合がありますwantarrayをその良いか悪い場合は...と、おそらくいくつかの議論へのリンク- PerlMonksに有害と考えられwantarrayをの使用

偶然にも、私はこれを私が構築しているJava Rest APIで扱っています。1つのリソースがXMLまたはJSONを返すことを可能にしました。その場合の最小公分母タイプはですString。現在、人々は戻り値の型に関するドキュメントを求めています。クラスを返すと、Javaツールで自動的に生成できますが、選択したためString、ドキュメントを自動的に生成できません。ストーリーの事後/道徳において、メソッドごとに1つのタイプを返したいと思います。
ダニエルカプラン14年

厳密には、これはオーバーロードの形になります。つまり、複数のフェデレーテッド機能があり、呼び出しの詳細に応じて、いずれかのバージョンが選択されます。
イアン14年

1

ダイナミックランドでは、すべてがアヒルのタイピングです。最も責任のある公開された公開されていることは、潜在的に異なるタイプをラッパーでラップして、それらに同じインターフェースを与えることです。

function ThingyWrapper(thingy){ //a function constructor (class-like thingy)

    //thingy is effectively private and persistent for ThingyWrapper instances

    if(typeof thingy === 'array'){
        this.alertItems = function(){
            thingy.forEach(function(el){ alert(el); });
        }
    }
    else {
        this.alertItems = function(){
            for(var x in thingy){ alert(thingy[x]); }
        }
    }
}

function gimmeThingy(){
    var
        coinToss = Math.round( Math.random() ),//gives me 0 or 1
        arrayThingy = [1,2,3],
        objectThingy = { item1:1, item2:2, item3:3 }
    ;

    //0 dynamically evaluates to false in JS
    return new ThingyWrapper( coinToss ? arrayThingy : objectThingy );
}

gimmeThingy().alertItems(); //should be same every time except order of numbers - maybe

ジェネリックラッパーを使用せずにさまざまなタイプを完全に引き出すのが理にかなっている場合がありますが、正直なところ、JSを書いてから7年が経ちました。ほとんどの場合、物事がまとめられているオブジェクトの内部のような閉じた環境のコンテキストで行うことです。しかし、例が思い浮かぶほど頻繁にやったことではありません。

ほとんどの場合、型について考えるのをやめることをお勧めします。動的言語で必要な場合は、型を扱います。もういや。それが全体のポイントです。すべての引数の型をチェックしないでください。それは、同じ方法で明らかでない方法で一貫性のない結果が得られる環境でのみやろうとすることです(そのようなことは絶対にしないでください)。しかし、それは重要なタイプではなく、あなたが私に与えたものがどのように機能するかです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.