2009-02-26 48 views
68

Tôi biết C# đang nhận được nhiều hỗ trợ lập trình song song, nhưng AFAIK vẫn không có cấu trúc để xác minh tác dụng phụ, phải không?Chức năng thuần túy trong C#

Tôi cho rằng sẽ khó khăn hơn khi C# đã được đặt. Nhưng có kế hoạch để có được điều này trong? Hoặc là F # ngôn ngữ .NET duy nhất có cấu trúc để xác minh tác dụng phụ?

Trả lời

156

C# ngôn ngữ không phải là, nhưng .NET framework có thể.

Các Hợp đồng thư viện + các công cụ phân tích tĩnh được giới thiệu trong .NET 4 có thể giới thiệu sau đây:

Microsoft đang sử dụng [Immutable] và [tinh khiết] bên trong .NET 3.5 framework ngay bây giờ.

Ví dụ: xem [Microsoft.Contracts.Immutable] và [Microsoft.Contracts.Pure] bên trong .NET 3.5, trong System.Core.dll. Thật không may, họ đang nội bộ. Tuy nhiên, Microsoft.Contracts. * Chủ yếu được sinh ra từ nghiên cứu SpeC#, và SpeC# đã được xếp vào các API hợp đồng sẽ là một phần của .NET 4.0.

Chúng tôi sẽ xem điều gì xảy ra với điều này. Tôi đã không kiểm tra xem các bản phát hành .NET 4.0 bit trước có chứa bất kỳ API nào như [Pure] hay [Immutable] trong API hợp đồng hay không. Nếu họ làm, tôi tưởng tượng công cụ phân tích tĩnh sẽ là công cụ để thực thi quy tắc, chứ không phải là trình biên dịch.

chỉnh sửa Tôi vừa tải lên Microsoft.Contracts.dll từ latest pre-release drop of MS Code Contracts tuần này. Tin tốt: Các thuộc tính [Pure] và [Mutability (Mutability.Immutable)] tồn tại trong thư viện, cho thấy chúng sẽ nằm trong .NET 4.0. Woohoo!

chỉnh sửa 2 Bây giờ .NET 4 đã được phát hành, tôi đã tra cứu các loại này. [Pure] vẫn còn trong System.Diagnostics.Contracts không gian tên. Nó không nhằm mục đích sử dụng chung, mà là để sử dụng với kiểm tra trước và sau điều kiện của API hợp đồng. Nó không phải là trình biên dịch được thi hành, neither does the Code Contract checker tool enforce purity. [Mutability] đã biến mất. Điều thú vị là, nơi Microsoft đã sử dụng các thuộc tính Mutability và Pure trong .NET 3.5 (trong lớp BigInteger bên trong trong System.Core.dll), .NET 4 đã chuyển BigInteger sang System.Numerics và đã loại bỏ [Pure] và [Mutability] các thuộc tính ngoài loại đó. Dòng dưới cùng: nó xuất hiện .NET 4 không làm gì để xác minh tác dụng phụ.

chỉnh sửa 3 Với thời gian gần đây (cuối năm 2011) xem trước Microsoft Rosyln biên dịch-như-một-dịch vụ công cụ - được cho là lên kế hoạch cho RTM trong Visual Studio 2015 - trông giống như họ sẽ có thể hỗ trợ những thứ như thế này; bạn có thể viết các phần mở rộng cho trình biên dịch để kiểm tra độ tinh khiết và bất biến, và phát hành cảnh báo trình biên dịch nếu một thứ gì đó được trang trí với các thuộc tính đó không tuân theo các quy tắc. Mặc dù vậy, chúng tôi đang xem xét một vài năm để hỗ trợ điều này.

chỉnh sửa 4 Bây giờ Rosyln đang ở đây vào mùa hè năm 2015, khả năng xây dựng phần mở rộng trình biên dịch cho thuần khiết/bất biến thực sự tồn tại. Tuy nhiên, điều đó không làm bất cứ điều gì cho mã khung hiện có, cũng như mã thư viện của bên thứ ba. Nhưng trên đường chân trời là C# 7 proposal for immutable types. Điều này sẽ được thực thi bởi trình biên dịch và sẽ giới thiệu một từ khóa bất biến mới từ khóa thành C# và thuộc tính [Không thể thay đổi] trong khuôn khổ .NET. Cách sử dụng:

// Edit #4: This is a proposed design for C# 7 immutable as of June 2015. 
// Compiler will implicitly mark all fields as readonly. 
// Compiler will enforce all fields must be immutable types. 
public immutable class Person 
{ 
    public Person(string firstName, string lastName, DateTimeOffset birthDay) 
    { 
     FirstName = firstName; // Properties can be assigned only in the constructor. 
     LastName = lastName; 
     BirthDay = birthDay; 
    } 

    public string FirstName { get; } // String is [Immutable], so OK to have as a readonly property 
    public string LastName { get; } 
    public DateTime BirthDay { get; } // Date is [Immutable] too. 
} 

chỉnh sửa 5 Đó là tháng 11 năm 2016, và nó xuất hiện loại không thay đổi được giảm từ C# 7. Luôn luôn có hy vọng cho C# 8. :-)

chỉnh sửa 6 Đó là tháng 11 năm 2017. C# 8 đang được xem đầy đủ, và trong khi chúng ta sẽ không có các hàm thuần túy, chúng ta sẽ có readonly structs. Điều này làm cho cấu trúc không thay đổi, cho phép tối ưu hóa một số trình biên dịch.

+1

Một lưu ý khác, khi thả tuần trước, [Pure] là công khai, nhưng [Mutability (...)] là nội bộ. Chúng tôi sẽ xem liệu điều này có thay đổi không. –

+0

Một điều cần lưu ý là liệu các thuộc tính này có nghĩa là để sử dụng chung hay không hoặc chúng chỉ được sử dụng trong các API hợp đồng. Tôi hy vọng họ thường hữu ích để được sử dụng trong một codebase, bất kể một là sử dụng các API System.Diagnostics.Contract thực tế. –

+65

+1 để cập nhật câu trả lời cho câu hỏi cổ đại khi thế giới thay đổi. – Emile

17

Không chỉ là không có gì để xác minh tác dụng phụ - thậm chí không có gì để xác minh rằng một loại là bất biến, đó là một bước nhỏ hơn dọc theo cùng một tuyến đường IMO.

Tôi không tin rằng có bất kỳ điều gì sắp xảy ra trong ống C# 4.0 (mặc dù tôi có thể dễ dàng bị sai). Tôi thực sự hy vọng rằng bất biến đó tạo ra tác động trong C# 5.0; chắc chắn Eric Lippert đã viết blog khá một chút về nó, và folks tại MS đã suy nghĩ về song song một số tiền hợp lý.

Xin lỗi, đây không phải là một bức ảnh đáng khích lệ hơn.

Chỉnh sửa: Judah's answer là sáng hơn đáng kể ... hỗ trợ khung có đủ tốt cho bạn không? :) (Tôi sẽ không hoàn toàn ngạc nhiên nếu một số khía cạnh của Hợp đồng Mã chưa sẵn sàng cho .NET 4.0, hãy nhớ bạn - nếu có lẽ họ giữ bản phát hành ban đầu tương đối nhỏ và tăng nó sau này.)

+0

Cảm ơn Jon. Cái nhìn sâu sắc của bạn luôn được chào đón :) Tôi chỉ muốn xem những gì đang xảy ra trên bộ phận đó. –

+1

Lượt xem chào mừng về câu trả lời này có hữu ích hay không hoặc liệu nó có nên bị xóa trong ánh sáng của Giu-đa hay không. Vui lòng xóa nó nếu thích hợp. –

+0

Tôi thực sự muốn nó nếu thời gian chạy sẽ đảm bảo độ tinh khiết và bất biến, giống như nó cho an toàn loại. Bằng cách đó bạn có thể xây dựng một ngôn ngữ thuần túy trên đầu trang của CLR và gọi một cách an toàn (hoặc được gọi từ) C#. –

14

Về nguyên tắc, xác minh xem điều gì đó không thay đổi được & liệu mã có thiếu tác dụng phụ hay không. Tất cả các trường của cấu trúc lớp/dữ liệu phải là chỉ đọc và loại của chúng phải là một đối tượng bất biến khác. Chúng tôi cũng cần một cách để đánh dấu một đại biểu là "thuần túy" (tác dụng phụ miễn phí), nhưng điều đó có lẽ là tất cả có thể.

Tuy nhiên, vấn đề là điều này thường quá hạn chế. Trong F #, bạn thường viết mã theo một hiệu ứng phụ miễn phí & phong cách không thay đổi, nhưng thường có lợi khi sử dụng một số đột biến cục bộ. Điều này không phá vỡ độ tinh khiết tổng thể (theo một nghĩa nào đó) và làm cho nó dễ dàng hơn để viết mã. Tuy nhiên, việc xác minh điều này tự động rất khó (có nghĩa là đó là một vấn đề lý thuyết thú vị ..)

Ví dụ, hoàn toàn tốt khi làm việc với mảng theo cách "thuần túy". Bạn có thể có các phương pháp như Array.map áp dụng một số chức năng cho tất cả các phần tử và trả về một mảng mới mà không sửa đổi bản gốc. Hàm này thay đổi mảng (vừa được tạo) trước khi trả về, nhưng mảng không bị đột biến ở bất kỳ nơi nào khác, vì vậy đây là nguyên tắc tinh khiết, nhưng khó xác minh (và đây là mẫu lập trình khá hữu ích trong F #).

Vì vậy, tôi nghĩ rằng có rất nhiều điều có thể được thực hiện, nhưng chỉ đơn giản là cấm tất cả các tác dụng phụ có thể không được tốt như nó xuất hiện. Điều tốt đẹp về hợp đồng là chúng có thể được sử dụng trong kịch bản này.

Các vấn đề liên quan