class 書き方 静的なアヒル型言語はありますか?




th:classappend (12)

メンバを宣言するときにインタフェースを指定できますか?

この質問をしばらく考えた後、静的な鴨のタイプの言語が実際に働くかもしれないということが私には起こりました。 コンパイル時に定義済みのクラスをインタフェースにバインドできないのはなぜですか? 例:

public interface IMyInterface
{
  public void MyMethod();
}

public class MyClass  //Does not explicitly implement IMyInterface
{
  public void MyMethod()  //But contains a compatible method definition
  {
    Console.WriteLine("Hello, world!");
  }
}

...

public void CallMyMethod(IMyInterface m)
{
  m.MyMethod();
}

...

MyClass obj = new MyClass();
CallMyMethod(obj);     // Automatically recognize that MyClass "fits" 
                       // MyInterface, and force a type-cast.

あなたはそのような機能をサポートする言語を知っていますか? JavaやC#で役に立ちますか? それは基本的に何らかの形で欠陥がありますか? MyClassをサブクラス化してインターフェースを実装するか、アダプターのデザインパターンを使用して同じことを達成できるとは思いますが、これらのアプローチは不必要な定型コードのように思えます。


この質問へのまったく新しい答え、 Goはまさにこの機能を持っています 。 私はそれが本当にクールで賢いと思うが(実際の生活の中でどのように再生されるのか興味を持っていると思うが)、それを考える上で名誉あることだと思う。

公式文書に書かれているように(Tour of Goの一環として、サンプルコード付き)

インタフェースは暗黙的に実装される

型は、そのメソッドを実装することによってインタフェースを実装します。 明示的な意図の宣言はなく、 "implements"キーワードはありません。

暗黙インタフェースは、インタフェースの定義をその実装から切り離します。インタフェースの実装は、事前配置なしに任意のパッケージに現れる可能性があります。


Visual Basic 9のプレリリース版は、ダイナミックインターフェイスを使用したスタティックダックタイピングをサポートしていましたが、時間通りに出荷するために機能*をカットしました。



C ++でテンプレートを使うのはどうですか?

class IMyInterface  // Inheritance from this is optional
{
public:
  virtual void MyMethod() = 0;
}

class MyClass  // Does not explicitly implement IMyInterface
{
public:
  void MyMethod()  // But contains a compatible method definition
  {
    std::cout << "Hello, world!" "\n";
  }
}

template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
  m.MyMethod();  // instantiation succeeds iff MyInterface has MyMethod
}

MyClass obj;
CallMyMethod(obj);     // Automatically generate code with MyClass as 
                       // MyInterface

私は実際にこのコードをコンパイルしていませんが、元の提案されている(しかし非動作の)コードのC ++化は実行可能であり、とても簡単だと思います。



ブーは間違いなく静的なアヒル型言語です: http : //boo.codehaus.org/Duck+Typing

抜粋:

BooはJavaやC#のように静的に型付けされた言語です。 これは、あなたのブーイングアプリケーションが、.NETやMonoのために他の静的型付け言語でコード化されたものと同じくらい速く動作することを意味します。 しかし、静的型付き言語を使用すると、時に必要な型宣言( "x as int"のように、booの型推論のためにしばしば必要ではない)と時には必要な型キャストを伴う柔軟で冗長なコーディングスタイルに制約されますキャスティングタイプ)。 Booの型推論のサポートと最終的にジェネリックはここで助けますが...

静的タイピングによって提供されるセーフティネットを放棄することが適切な場合もあります。 おそらく、メソッドシグネチャについてあまり心配することなく、あるいはCOMオブジェクトなどの外部コンポーネントと会話するコードを作成していても、APIを探索したいと思うかもしれません。 いずれにせよ、選択肢はあなたのものでなければならない。

オブジェクト、int、文字列などの通常の型に加えて、booには "duck"という特別な型があります。 この用語は、ルビープログラミング言語のダックタイピング機能(「ダックのように歩き、アヒルのように歩くなら、それはアヒルでなければならない」)からインスピレーションを得ています。


新しいバージョンのC ++は静的なダックタイピングの方向に動いています。 あなたはいつか(今日?)次のようなことを書くことができます:

auto plus(auto x, auto y){
    return x+y;
}

x+y対応する関数呼び出しがない場合、コンパイルに失敗します。

あなたの批判については:

新しい「CallMyMethod」が渡される異なるタイプごとに作成されるため、実際にタイプ推論ではありません。

しかし、それは型推論です( fooがテンプレート化された関数であるfoo(bar)と言うことができます)。また、時間効率が良く、コンパイルされたコードでより多くのスペースを必要とする点を除いて同じ効果があります。

それ以外の場合は、実行時にメソッドをルックアップする必要があります。 あなたは名前を見つけて、その名前が正しいパラメータを持つメソッドを持っていることを確認する必要があります。

または、一致するインターフェースに関するすべての情報を保管し、インターフェースに一致するすべてのクラスを調べ、そのインターフェースを自動的に追加する必要があります。

どちらの場合でも、暗黙的かつ偶発的にクラス階層を壊すことができます。これはC#/ Javaのプログラマーの習慣に慣れているため、新しい機能には悪いことです。 C ++のテンプレートでは、あなたはすでに地雷にいることを知っています(テンプレートパラメータの制限を可能にするための機能(概念)も追加しています)。


タイプスクリプト!

さて、これはjavascriptのスーパーセットで、おそらく "言語"を構成しませんが、この種の静的なダックタイピングはTypeScriptでは不可欠です。


F#は静的なダックタイピングをサポートしていますが、キャッチではメンバの制約を使用する必要があります。 詳細はこのブログのエントリーにあります。

引用されたブログの例:

let inline speak (a: ^a) =
    let x = (^a : (member speak: unit -> string) (a))
    printfn "It said: %s" x
    let y = (^a : (member talk: unit -> string) (a))
    printfn "Then it said %s" y

type duck() =
    member x.speak() = "quack"
    member x.talk() = "quackity quack"
type dog() =
    member x.speak() = "woof"
    member x.talk() = "arrrr"

let x = new duck()
let y = new dog()
speak x
speak y

MLファミリの言語のほとんどは、 推論や制約付きのスキームを持つ構造型をサポートしています。これは元の質問で「静的なダックタイピング」という言葉が意味するような、奇妙な言語設計者の用語です。

このファミリーには、ハスケル、Objective Caml、F#、Scalaなどの言語が盛り込まれています。 もちろん、あなたの例に最もよく合致するのはObjective Camlでしょう。 あなたの例の翻訳があります:

open Printf

class type iMyInterface = object
  method myMethod: unit
end

class myClass = object
  method myMethod = printf "Hello, world!"
end

let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod

let myClass = new myClass

callMyMethod myClass

注意:使用した名前の中には、OCamlの識別子の大文字と小文字の区別の概念に準拠するために変更する必要があるものもありますが、それ以外の場合はかなり簡単な翻訳です。

また、 callMyMethod関数の型アノテーションもiMyInterfaceクラス型の定義も厳密には必要ありません。 Objective Camlは、型宣言なしであなたの例のすべてを推論することができます。


静的型付き言語は、定義により、 実行時ではなくコンパイル時に型をチェックします 。 上記のシステムの明らかな問題の1つは、実行時ではなくコンパイル時にコンパイラが型をチェックすることです。

さて、あなたは、コンパイラに明示的に型を宣言させるのではなく、型を派生させることができるように、より多くの情報をコンパイラに組み込むことができます。 コンパイラはMyClassMyMethod()メソッドを実装していることを知ることができ、それに応じてこのケースを適切に処理することができMyMethod() MyClassどおり)。 このようなコンパイラは、 Hindley-Milnerのような型推論を利用することができます。

もちろん、Haskellのようないくつかの静的型言語は、あなたが提案したものと同じようなことを既にしています。 Haskellコンパイラは、明示的に宣言する必要なしに(ほとんどの場合)型を推論することができます。 しかし明らかに、Java / C#にはこの能力がありません。






static-typing