静的または動的であることは、言語で完全にサポートされるものでなければなりません。静的と動的は、基本的に2つの言語を切り替えて、オンとオフを切り替える必要があるものではありません。
私はこのような本格的な混合型タイピングの狂気を話している:
class MyClass {
function myMethod(x: int, y: int){ # one parameter is typed, the other not
return <cast_to_int> y.return_integer(x); #casting to guarantee the contract
}
}
MyClass static_obj = MyClass(); #statically typed instantiation;
var dynamic_obj = {}; #dynamically typed instantiation
dynamic_obj.return_integer = (function (x) {return x*2}) #dynamic method creation
static_obj.myMethod(3, dynamic_obj) # This returns 6
dynamic_obj.return_integer = (function (x) {return x+1}); # dynamic member reassignment
static_obj.myMythod(3, dynamic_obj) # this returns 4
static_obj.myMethod('asdf', dynamic_obj) # This can't compile, because of typing
# and also this crazy thing; Notice that the static interface of the method is respected
if (<user input> == 2){
static_obj.myMethod = (function (x: int, y){return x + y.yet_some_other_method(x);})
}
# but when the static contract is not respected, it doesn't compile
static_obj.myMethod = (function (a, b, c) {return 'asdf'}) # Compile time error
このトピックに興味があるのは、静的言語でのAPIの発見可能性が素晴らしい(Java、C#、およびABAPについてしばらく好きだった)ので本当に気に入っていますが、実行時のテスト、サルのパッチ、REPL、再割り当ても好きです。 、そしてクレイジーなリフレクションマジック(JavaScriptとPythonについて私が気に入った)。
私はDartの静的型チェッカーを知っていますが、実際の静的な保証を提供しないため、それだけでは十分ではありません。
また、型推論には興味がありません。真の動的動作の次に真の静的実行が必要です。私はまた、Pythonのdict
、JSオブジェクト、またはJavaのHashMapなどのマッピングタイプを使用してデータ(または関数)を渡すことができることも知っていますが、Javaのマッピングはそれらにメソッドを運ぶことができません。 dictsには(すぐに)メソッドを含めることはできません。JSはあらゆる種類の静的な制限を単純に笑っていますが、this
キーワードを介してコンテキストオブジェクトにアクセスできるメソッドを実行時に追加すると、本当にクールなもの(Pythonは、クラスインスタンスにではなく、クラスオブジェクトに関数を追加するときにも実行します)を知っています)。
私の好奇心はこの論文によっても引き起こされました: 可能な場合は静的型付け、必要な場合は動的型付け
そして、APIの発見可能性の議論は私自身の経験から来ましたが、このペーパーはそれをサポートしているようです: http://personales.dcc.uchile.cl/~rrobbes/p/ICPC2014-idetypes.pdf
はい。 4.0以降のC#は、dynamic
キーワードを使用した最も一般的な例です。私が忘れている、または知らない他の良い例がおそらくあります。
この良い例が Dylan です。あなたはディランで静的および動的タイピングを使用することができます、例えば、
define method double(a :: <integer>) => (result :: <integer>)
2 * a
end
または
define method double(a) => (result)
2 * a
end
これは変数などにも適用されます。別のより穏やかな例はREBOLですが、その関数定義のみで、たとえば、
double: func [a [integer!]] [a * 2]
double: func [a] [a * 2]
関数パラメーターは、REBOL内で唯一、あらゆる種類の型チェック(または、宣言)が許可されています。
クラシックVisual BasicとVBAは、この機能を最初から備えています。
VB.NETには、リリース(1.0)からもこの機能があり、プロジェクトプロパティのコードファイルまたはプロジェクト全体でOption Strict On
ステートメントを使用して「スイッチを切る」オプションがありました。これは実際にはオフに切り替えないため、これがオンの場合、遅延バインディングステートメントをコンパイルしません。
C#は最終的にバージョン4.0の後半に追いつきましたが、動的キーワードを使用して「許可」する必要があるという違いがあります。
JavaはこれをObject
クラスで持っています。
int myMethod(int x, Object y) {
return x > 0 ? x : (int)y;
}
void go() {
Object obj;
if(Math.random() > 0.5)
obj = 3;
else
obj = "hello";
myMethod(-5, obj); // throws ClassCastException if obj is a String
}
Java 8では、ラムダ関数が導入されているため、関数をマップ内に配置できますが、少し扱いにくいです。
Map myObj = new HashMap();
myObj.put("add",
(BiFunction) (Object x, Object y) -> ((Number) x).intValue() + ((Number) y).intValue());
BiFunction addition = (BiFunction) myObj.get("add");
int apply = (int) (Number) addition.apply(3, 2.2);