2008-11-14 6 views
14

Can I specify interfaces when I declare a member?Có ngôn ngữ gõ vịt tĩnh nào không?

Sau khi suy nghĩ về câu hỏi này trong một thời gian, điều đó xảy ra với tôi rằng ngôn ngữ tĩnh-vịt có thể thực sự hoạt động. Tại sao các lớp không được định nghĩa trước bị ràng buộc vào một giao diện tại thời gian biên dịch? Ví dụ:

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. 

Bạn có biết bất kỳ ngôn ngữ nào hỗ trợ tính năng này không? Nó có hữu ích trong Java hay C#? Về cơ bản nó có thiếu sót không? Tôi hiểu rằng bạn có thể phân lớp MyClass và triển khai giao diện hoặc sử dụng mẫu thiết kế Bộ điều hợp để thực hiện điều tương tự, nhưng những cách tiếp cận đó có vẻ như mã soạn sẵn không cần thiết.

Trả lời

9

Ngôn ngữ được nhập tĩnh, theo định nghĩa, các loại séc tại thời gian biên dịch, không phải thời gian chạy. Một trong những vấn đề hiển nhiên với hệ thống được mô tả ở trên là trình biên dịch sẽ kiểm tra các loại khi chương trình được biên dịch, không phải lúc chạy.

Bây giờ, bạn có thể xây dựng nhiều thông minh hơn vào trình biên dịch để có thể lấy được các loại, thay vì yêu cầu lập trình viên rõ ràng khai báo các loại; trình biên dịch có thể thấy rằng MyClass triển khai phương thức MyMethod() và xử lý trường hợp này cho phù hợp, mà không cần cần phải khai báo giao diện một cách rõ ràng (như bạn đề xuất). Trình biên dịch như vậy có thể sử dụng suy luận kiểu, chẳng hạn như Hindley-Milner.

Tất nhiên, một số ngôn ngữ được nhập tĩnh như Haskell đã làm điều gì đó tương tự với những gì bạn đề xuất; trình biên dịch Haskell có thể suy ra các kiểu (hầu hết thời gian) mà không cần khai báo chúng một cách rõ ràng. Nhưng rõ ràng, Java/C# không có khả năng này.

+0

Cảm ơn bạn. Tôi vừa mới bắt đầu học Haskell khoảng một tuần trước và cho đến nay nó có vẻ khá thú vị. Đó là một chút của một đường cong học tập mặc dù - không bao giờ thực sự có vào các ngôn ngữ chức năng trước đây. Dù sao, hệ thống suy luận kiểu của nó rất giống với những gì tôi đang đề cập đến. – Cybis

+3

C# dường như có suy luận Loại. Ví dụ, bài viết này nói về nó. http://www.developer.com/net/csharp/article.php/3601646/Go-Inside-C-30s-Type-Inference-Process.htm –

9

Tôi không thấy điểm. Tại sao không rõ ràng rằng lớp thực hiện giao diện và đã thực hiện với nó? Thực hiện giao diện là những gì nói với các lập trình viên khác rằng lớp này được cho là hành xử theo cách mà giao diện xác định. Đơn giản chỉ cần có cùng tên và chữ ký trên một phương thức truyền tải không đảm bảo rằng mục đích của nhà thiết kế là thực hiện các hành động tương tự với phương thức. Điều đó có thể xảy ra, nhưng tại sao lại để giải thích (và lạm dụng)?

Lý do bạn có thể "thoát khỏi" với thành công này bằng ngôn ngữ động có liên quan nhiều đến TDD hơn là với chính ngôn ngữ đó. Theo ý kiến ​​của tôi, nếu ngôn ngữ cung cấp cho cơ sở để cung cấp cho các loại hướng dẫn cho những người khác sử dụng/xem mã, bạn nên sử dụng nó. Nó thực sự cải thiện sự rõ ràng và đáng giá thêm vài ký tự. Trong trường hợp bạn không có quyền truy cập để thực hiện điều này, thì Bộ điều hợp phục vụ cùng mục đích tuyên bố rõ ràng cách giao diện liên quan đến lớp kia.

+0

Tôi đồng ý, đó là quan điểm của một giao diện, để mô tả là những gì một cái gì đó. Sử dụng nó bất cứ nơi nào bạn có thể, nó không phải là mã soạn sẵn, thực hành tốt của nó. – Mark

+2

Tại sao mẫu này thành công trong ngôn ngữ động, nhưng sẽ được coi là thực hành không tốt trong các ngôn ngữ tĩnh? TDD phải làm gì với nó là duy nhất để gõ động? Như @mipadi đã đề cập, tại sao ngôn ngữ OO không thể hỗ trợ một loại hệ thống suy luận kiểu Haskell? – Cybis

+0

Từ sự hiểu biết hạn chế của tôi về nó, Generics Java chỉ là một vòng về cách làm những gì số tiền để loại vịt. –

1

Thiết kế tiền phát hành cho Visual Basic 9 có hỗ trợ nhập vịt tĩnh bằng giao diện động nhưng họ đã cắt tính năng * để vận chuyển đúng giờ.

2

Boo chắc chắn là một ngôn ngữ vịt-gõ tĩnh: http://boo.codehaus.org/Duck+Typing

Một đoạn trích:

Boo is a statically typed language, like Java or C#. This means your boo applications will run about as fast as those coded in other statically typed languages for .NET or Mono. But using a statically typed language sometimes constrains you to an inflexible and verbose coding style, with the sometimes necessary type declarations (like "x as int", but this is not often necessary due to boo's Type Inference) and sometimes necessary type casts (see Casting Types). Boo's support for Type Inference and eventually generics help here, but...

Sometimes it is appropriate to give up the safety net provided by static typing. Maybe you just want to explore an API without worrying too much about method signatures or maybe you're creating code that talks to external components such as COM objects. Either way the choice should be yours not mine.

Along with the normal types like object, int, string...boo has a special type called "duck". The term is inspired by the ruby programming language's duck typing feature ("If it walks like a duck and quacks like a duck, it must be a duck").

+1

Một ngôn ngữ tĩnh với cách gõ vịt không giống như vịt tĩnh đánh máy. Cả hai VB hiện tại và sắp tới C# 4.0 có gõ tĩnh và động/cuối ràng buộc/vịt gõ –

+0

Tôi không có nghĩa là một kết hợp của gõ tĩnh và năng động (mà có vẻ là những gì bạn đang đề cập đến, torial). Tôi đang đề cập đến kiểu suy luận - trình biên dịch có thể thấy ngay lập tức rằng MyClass và IMyInterface tương thích mà không có lập trình viên làm cho mối quan hệ rõ ràng. – Cybis

+0

Tệ của tôi. Boo sẽ không làm điều đó cho bạn. – torial

8

F # hỗ trợ gõ vịt tĩnh, mặc dù với một nhược điểm: bạn phải sử dụng hạn chế thành viên. Chi tiết có sẵn trong số blog entry này.

Ví dụ từ blog được trích dẫn:

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 
12

Làm thế nào về việc sử dụng mẫu trong 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 

Tôi chưa thực sự biên soạn mã này, nhưng tôi tin rằng nó hoàn toàn khả thi và mã C++ - ization rất nhỏ của mã được đề xuất ban đầu (nhưng không hoạt động).

+1

Ai đó đã đề cập đến các mẫu C++, nhưng tôi nghĩ rằng câu trả lời đã bị xóa. Dù sao, các mẫu về cơ bản chỉ là các macro nâng cao. Một mới "CallMyMethod" được tạo ra cho mỗi loại khác nhau bạn vượt qua nó, vì vậy nó không thực sự loại suy luận. – Cybis

+0

Hơn nữa, tôi không biết về một IDE C++ tốt với intellisense mà không bị lẫn lộn trên các mẫu (Visual Studio không phải lúc nào cũng liệt kê tất cả các lựa chọn, và đôi khi nó dừng hoàn toàn). – Cybis

+1

Để công bằng, áp phích ban đầu không đề cập đến suy luận kiểu * mỗi lần *. Tôi chỉ cần chỉnh mã của mình một chút và cho thấy rằng nó có thể làm việc trong C++ khá nhiều như-là. –

4

Hầu hết các ngôn ngữ trong việc hỗ trợ gia đình ML loại cấu trúc với suy luận và các đề án loại hạn chế, đó là geeky ngôn ngữ thiết kế các thuật ngữ mà dường như nhiều khả năng những gì bạn có ý nghĩa bởi cụm từ "tĩnh gõ vịt "trong câu hỏi ban đầu.

Các ngôn ngữ phổ biến hơn trong gia đình này mà bạn nghĩ đến bao gồm: Haskell, Caml mục tiêu, F # và Scala. Một trong đó phù hợp nhất với ví dụ của bạn, tất nhiên, sẽ là mục tiêu Caml. Dưới đây là một bản dịch của ví dụ của bạn:

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 

Lưu ý: một số tên bạn sử dụng phải được thay đổi để phù hợp với khái niệm về trường hợp nhận dạng ngữ nghĩa OCaml, nhưng bằng cách khác, đây là một bản dịch khá đơn giản.

Ngoài ra, đáng chú ý, không phải chú thích loại trong hàm callMyMethod cũng không phải định nghĩa của loại lớp iMyInterface là cần thiết. Caml mục tiêu có thể phỏng đoán mọi thứ trong ví dụ của bạn mà không có bất kỳ khai báo kiểu nào cả.

15

Câu trả lời hoàn toàn mới cho câu hỏi này, Go has exactly this feature. Tôi nghĩ rằng nó thực sự mát mẻ & thông minh (mặc dù tôi sẽ được quan tâm để xem làm thế nào nó diễn ra trong cuộc sống thực) và kudo về suy nghĩ của nó.

Như ghi nhận in the official documentation (as part of the Tour of Go, with example code):

Interfaces are implemented implicitly

A type implements an interface by implementing its methods. There is no explicit declaration of intent, no "implements" keyword.

Implicit interfaces decouple the definition of an interface from its implementation, which could then appear in any package without prearrangement.

+0

Bạn có thể liên kết đến phần thực tế của tài liệu Go để giải thích cách hoạt động của tài liệu này không? Và, thậm chí tốt hơn, bao gồm một ví dụ ở đây? –

+1

Như bạn muốn (nhưng chỉ được liên kết với ví dụ) – Grumdrig

0

Trong phiên bản mới nhất của ngôn ngữ lập trình của tôi Heron nó hỗ trợ cái gì đó tương tự thông qua một sự ép buộc cấu trúc-subtyping điều hành gọi as. Vì vậy, thay vì:

MyClass obj = new MyClass(); 
CallMyMethod(obj); 

Bạn sẽ viết:

MyClass obj = new MyClass(); 
CallMyMethod(obj as IMyInterface); 

Cũng giống như trong ví dụ của bạn, trong trường hợp này MyClass không nhất thiết phải thực hiện một cách rõ ràng IMyInterface, nhưng nếu nó đã làm các diễn viên có thể xảy ra ngầm và các nhà điều hành as có thể được bỏ qua.

Tôi đã viết nhiều hơn một chút về kỹ thuật mà tôi gọi là nhập cấu trúc con rõ ràng trong this article.

1

Phiên bản mới của C++ di chuyển theo hướng gõ vịt tĩnh. Bạn có thể một ngày nào đó (? Ngày nay) viết một cái gì đó như thế này:

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

và nó sẽ không biên dịch nếu không có phù hợp với chức năng gọi cho x+y.

Đối với những lời chỉ trích của bạn:

A new "CallMyMethod" is created for each different type you pass to it, so it's not really type inference.

nhưng nó là loại suy luận (bạn có thể nói foo(bar) nơi foo là một chức năng templated), và có tác dụng tương tự, ngoại trừ đó là có thêm thời gian hiệu quả và có nhiều không gian hơn trong mã được biên dịch.

Nếu không, bạn sẽ phải tra cứu phương pháp trong khi chạy. Bạn sẽ phải tìm một tên, sau đó kiểm tra xem tên có phương thức có thông số đúng hay không.

Hoặc bạn sẽ phải lưu trữ tất cả thông tin đó về giao diện phù hợp và xem xét mọi lớp khớp với giao diện, sau đó tự động thêm giao diện đó.

Trong cả hai trường hợp, điều này cho phép bạn ngầm và vô tình phá vỡ phân cấp lớp, điều này không tốt cho một tính năng mới vì nó đi ngược lại thói quen của những lập trình viên C#/Java được sử dụng. Với các mẫu C++, bạn đã biết bạn đang ở trong một bãi chứa (và chúng cũng thêm các tính năng ("khái niệm") để cho phép các hạn chế về các tham số mẫu).

2

TypeScript!

Vâng, ok ... Vì vậy, nó là một superset javascript và có lẽ không phải là một "ngôn ngữ", nhưng loại này của tĩnh vịt-gõ là quan trọng trong việc đánh máy.

enter image description here

1

Crystal là một ngôn ngữ tĩnh vịt-gõ. Example:

def add(x, y) 
    x + y 
end 

add(true, false) 

Các cuộc gọi đến add nguyên nhân này lỗi biên dịch:

Error in foo.cr:6: instantiating 'add(Bool, Bool)' 

add(true, false) 
^~~ 

in foo.cr:2: undefined method '+' for Bool 

    x + y 
    ^