Bất biến đã được hiểu rõ trong một thời gian. Python, Java và C ++ có các mô hình bộ nhớ khác nhau khiến việc so sánh trực tiếp trở nên khó khăn. Tác giả của bài báo mà bạn trích dẫn ban đầu dường như không biết C ++.
Như trong Python, Java và hầu hết các ngôn ngữ đa mô hình, C và C ++ cho phép khả năng biến đổi theo mặc định. Đây là những gì lập trình viên thường muốn: nếu tôi có một String x
biến, tôi muốn có thể gán một giá trị mới x = "foo"
.
Hệ thống const trong C và C ++ cho phép rất nhiều tính bất biến sắc thái thiếu trong Python, Java và thậm chí là Scala. Nếu một hàm C ++ mất một const std::string&
hoặc a const char*
, nó hứa hẹn (và trình biên dịch đảm bảo, ở một mức độ nào đó), rằng hàm này sẽ không (không thể!) Thay đổi nội dung của chuỗi đó. Cho một đối tượng const, chúng ta chỉ có thể gọi các phương thức của đối tượng đó cũng được đánh dấu là const. Nếu một lớp C ++ chỉ có các thành viên công khai const
, thì đối tượng đó là bất biến.
Tuy nhiên, điều này đôi khi gây nhầm lẫn vì trong các đối tượng C và C ++ là các vị trí bộ nhớ và các biến là tên cho các vị trí bộ nhớ. Ngược lại, các biến trong Python và Java là tên của các con trỏ tới các đối tượng. Trong một ngôn ngữ có ngữ nghĩa tham chiếu, x = y
có nghĩa là tạo ra điểm x cho cùng một đối tượng như y. Vì chúng tôi chỉ sao chép con trỏ, điều này là có thể với các đối tượng bất biến. Trong một ngôn ngữ có ngữ nghĩa giá trị như C ++, điều đó có nghĩa là Cập nhật nội dung x
với nội dung của y
Trực tiếp. Do đó, nếu việc gán lại một biến được mong muốn trong C hoặc C ++, biến đó có thể không có kiểu const. Để làm điều này với các đối tượng bất biến, chúng ta sẽ phải sử dụng một con trỏ rõ ràng.
Việc Java và Python sử dụng các đối tượng chuỗi bất biến là một quyết định thiết kế cơ bản, nhưng nó không được kết nối trực tiếp với lợi ích của tính bất biến trong môi trường đa luồng. Một lý do là chuỗi ký tự trong mã nguồn có thể được gộp lại làm giảm số lượng đối tượng. Điều này cũng có thể có trong C / C ++. Trong C ++, nghĩa đen "foo"
có loại const char[4]
(char thứ 4 là chấm dứt '\0'
). Một lý do khác là các mục trong bộ và khóa trong dicts / maps không được thay đổi. Vì các chuỗi được sử dụng phổ biến như các khóa dict (hầu hết các đối tượng Python là một dict), tính không thay đổi sẽ loại bỏ một nguồn lỗi phổ biến. Trong Java, một lý do khác cho các chuỗi bất biến là mô hình bảo mật Java. Tất cả những lý do này hoàn toàn không liên quan đến đa luồng.
Nếu Java được xây dựng với ý tưởng bất biến, ngôn ngữ sẽ có vẻ rất khác. Mặc dù được truyền cảm hứng chặt chẽ bởi C ++, các nhà thiết kế đã cố gắng tạo ra một ngôn ngữ đơn giản hơn nhiều, loại bỏ const là một bước như vậy. Điều Java tương đương với tham chiếu const C ++ là một bộ điều hợp hoặc trình trang trí thực hiện bất kỳ phương thức đột biến nào throws new NotImplementedException()
và chuyển tiếp các phương thức không biến đổi gọi đến bộ sưu tập thực tế. Thực tế là tất cả các giao diện bộ sưu tập java.util đều ngụ ý khả năng biến đổi là một dấu hiệu rõ ràng mà họ đã không cố gắng cho một ngôn ngữ đầu tiên không thay đổi.
Giải pháp mà Java đưa ra để giải quyết các vấn đề tương tranh không phải là bất biến, mà là khóa phổ biến. Mỗi đối tượng chứa một mutex có thể được sử dụng cho synchronized
các khối hoặc toàn bộ phương thức. Hóa ra, điều đó không tốt cho hiệu suất, không mở rộng rất tốt và khá dễ bị lỗi - bạn vẫn phải đối phó với trạng thái toàn cầu có thể thay đổi.