Làm thế nào để các đặc điểm trong Scala tránh được lỗi kim cương của Wap?


16

(Lưu ý: Tôi đã sử dụng 'lỗi' thay vì 'vấn đề' trong tiêu đề vì lý do rõ ràng ..;)).

Tôi đã đọc một số bài cơ bản về Đặc điểm trong Scala. Chúng tương tự như Giao diện trong Java hoặc C #, nhưng chúng cho phép thực hiện mặc định một phương thức.

Tôi đã tự hỏi: điều này không thể gây ra một trường hợp của "vấn đề kim cương", đó là lý do tại sao nhiều ngôn ngữ tránh được nhiều sự kế thừa ở nơi đầu tiên?

Nếu vậy, Scala xử lý việc này như thế nào?


Chia sẻ nghiên cứu của bạn giúp mọi người . Hãy cho chúng tôi những gì bạn đã cố gắng và tại sao nó không đáp ứng nhu cầu của bạn. Điều này chứng tỏ rằng bạn đã dành thời gian để cố gắng tự giúp mình, nó giúp chúng tôi tránh nhắc lại các câu trả lời rõ ràng và hầu hết nó giúp bạn có được câu trả lời cụ thể và phù hợp hơn. Xem thêm Cách hỏi
gnat

2
@gnat: đây là một câu hỏi khái niệm, không phải là một câu hỏi cụ thể. Nếu anh ta hỏi "Tôi có lớp học này ở Scala và nó mang đến cho tôi những vấn đề mà tôi nghĩ có thể liên quan đến Vấn đề Kim cương, làm thế nào để tôi khắc phục nó?" thì bình luận của bạn sẽ phù hợp, nhưng sau đó câu hỏi sẽ thuộc về SO. : P
Mason Wheeler

@MasonWheeler Tôi cũng đã đọc một số bài cơ bản về Scala. Và lần đầu tiên tìm kiếm "kim cương" trong những gì tôi đã đọc đã cho tôi câu trả lời: "Một đặc điểm có tất cả các tính năng của cấu trúc giao diện Java. Nhưng các đặc điểm có thể đã thực hiện các phương thức trên chúng. Nếu bạn quen thuộc với Ruby, các đặc điểm tương tự với mixins của Ruby. Bạn có thể trộn nhiều đặc điểm vào một lớp. Các đặc điểm không thể lấy tham số của hàm tạo, nhưng khác với chúng hoạt động giống như các lớp. Điều này cho bạn khả năng tiếp cận nhiều kế thừa mà không gặp vấn đề kim cương ". Thiếu nỗ lực trong câu hỏi này cảm thấy khá trắng trợn
gnat

7
Đọc câu nói đó không cho bạn biết NHƯ THẾ NÀO.
Michael Brown

Câu trả lời:


21

Vấn đề kim cương là không có khả năng quyết định thực hiện phương pháp nào để lựa chọn. Scala giải quyết điều này bằng cách xác định lựa chọn triển khai nào là một phần của thông số kỹ thuật ngôn ngữ ( đọc phần về Scala trong bài viết Wikipedia này ).

Tất nhiên, định nghĩa thứ tự tương tự cũng có thể được sử dụng trong thừa kế nhiều lớp, vậy tại sao phải bận tâm với các đặc điểm?

Lý do IMO là các nhà xây dựng. Trình xây dựng có một số hạn chế mà các phương thức thông thường không có - chúng chỉ có thể được gọi một lần cho mỗi đối tượng, chúng phải được gọi cho mỗi đối tượng mới và hàm tạo của lớp con phải gọi hàm tạo của cha mẹ là hướng dẫn đầu tiên (hầu hết các ngôn ngữ sẽ làm điều đó ngầm cho bạn nếu bạn không cần truyền tham số).

Nếu B và C thừa hưởng A và D kế thừa B và C, và cả hai hàm tạo của B và C đều gọi hàm tạo của A, thì hàm tạo của D sẽ gọi hàm tạo của A hai lần. Xác định việc triển khai nào để chọn như Scala đã làm với các phương thức sẽ không hoạt động ở đây vì cả hai hàm tạo của B và C phải được gọi.

Đặc điểm tránh vấn đề này vì họ không có nhà xây dựng.


1
Có thể sử dụng tuyến tính hóa C3 để gọi các hàm tạo một lần và chỉ một lần - đó là cách Python thực hiện nhiều kế thừa. Ngoài đỉnh đầu tôi, việc tuyến tính hóa cho D <B | C <Một viên kim cương là D -> B -> C -> A. Hơn nữa, một tìm kiếm trên google đã cho tôi thấy rằng các đặc điểm của Scala có thể có các biến đổi, vì vậy chắc chắn có một nhà xây dựng ở đâu đó trong đó? Nhưng nếu nó sử dụng bố cục dưới mui xe (tôi không biết, không bao giờ sử dụng Scala) thì không khó để thấy rằng B và C có thể chia sẻ trên ví dụ của A ...
Doval

... Các đặc điểm có vẻ như là một cách rất ngắn gọn để diễn tả tất cả các mẫu soạn sẵn kết hợp kế thừa giao diện và bố cục + ủy quyền, đây là cách chính xác để sử dụng lại hành vi.
Doval

@Doval Kinh nghiệm của tôi về các nhà xây dựng trong Python được thừa hưởng nhiều lần là họ là một nỗi đau của hoàng gia. Mỗi hàm tạo không thể biết nó sẽ được gọi theo thứ tự nào, vì vậy không biết chữ ký của hàm tạo của nó là gì. Giải pháp thông thường là cho mọi nhà xây dựng lấy một loạt các đối số từ khóa và chuyển những đối số không sử dụng lên siêu xây dựng của nó, nhưng nếu bạn cần làm việc với một lớp hiện có không tuân theo quy ước đó, bạn không thể kế thừa một cách an toàn nó
James_pic

Một câu hỏi khác là tại sao C ++ không chọn chính sách lành mạnh cho vấn đề kim cương?
người dùng

20

Scala tránh được vấn đề kim cương bằng một thứ gọi là "tuyến tính hóa đặc điểm". Về cơ bản, nó tìm kiếm phương thức thực hiện trong các đặc điểm bạn mở rộng từ phải sang trái. Ví dụ đơn giản:

trait Base {
   def op: String
}

trait Foo extends Base {
   override def op = "foo"
}

trait Bar extends Base {
   override def op = "bar"
}

class A extends Foo with Bar
class B extends Bar with Foo

(new A).op
// res0: String = bar

(new B).op
// res1: String = foo

Có nói rằng, danh sách các đặc điểm mà nó tìm kiếm có thể chứa nhiều hơn những đặc điểm bạn đưa ra rõ ràng, vì chúng có thể mở rộng các đặc điểm khác. Một lời giải thích chi tiết được đưa ra ở đây: Đặc điểm là sửa đổi có thể xếp chồng và một ví dụ đầy đủ hơn về tuyến tính hóa ở đây: Tại sao không phải là nhiều kế thừa?

Tôi tin vào các ngôn ngữ lập trình khác, hành vi này đôi khi được gọi là "Thứ tự giải quyết phương pháp" hoặc "MRO".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.