Hệ thống phân loại kiểu dữ liệu: Structural vs Nominal

  1. Lập trình

Một thuộc tính quan trọng của mọi hệ thống phân loại kiểu là liệu chúng phân loại dạng cấu trúc hay định danh, hoặc trong hệ thống đơn giản thì có thể sử dụng cả hai dạng kiểm tra kiểu dữ liệu ấy. Vì vậy, điều quan trọng là phải nhận biết được sự khác biệt.

(Bài viết được dịch và hiệu đính từ bản gốc -

Type Systems: Structural vs. Nominal typing explained
).

775700108f0c11e89e88f5f510f26499

Một kiểu dữ liệu có thể là một chuỗi, logic, đối tượng hoặc lớp. Chúng có tên và cấu trúc. Các kiểu cơ bản như chuỗi hoặc logic đều có cấu trúc rất đơn giản và được thể hiện qua tên.


Các kiểu như đối tượng hoặc các lớp có cấu trúc phức tạp hơn. Chúng đều có tên định danh riêng ngay cả khi chúng có cùng một cấu trúc.


Trình kiểm tra kiểu dữ liệu tĩnh dùng định danh hoặc cấu trúc, các kiểu dữ liệu sẽ được kiểm tra qua định danh nếu sử dụng kiểu kiểm tra thông qua tên định danh đã quy định trước hoặc kiểm tra qua dạng cấu trúc.


Định danh:

Các ngôn ngữ như C++, Java và Swift có các hệ thống phân loại kiểu theo dạng định danh.

1

Bạn có thể thấy mã giả ở ví dụ trên là một mô phỏng dạng kiểm tra kiểu dữ liệu theo hướng định danh bị lỗi khi bạn đang cố gắng khai báo đối tượng Bar cho một đối tượng Foo. Chúng có tên khác nhau.  


Cấu trúc:

Các ngôn ngữ như OCaml, Haskell và Elm có các hệ thống phân loại kiểu theo dạng cấu trúc.

2

Bạn có thể thấy mã giả ở ví dụ trên là một mô phỏng dạng kiểm tra kiểu dữ liệu theo hướng cấu trúc thành công khi bạn đang cố gắng khai báo đối tượng Bar cho một đối tượng Foo. Chúng có cấu trúc giống nhau.  


Tuy nhiên, ngay sau khi bạn thay đổi cấu trúc bên trọng thì ngay lập tức xảy ra lỗi.

3

Nó có thể phức tạp hơn một chút


Chúng ta có thể thấy cả hai dạng định danh và cấu trúc trong ví dụ trên, nhưng cũng có các loại phức tạp khác như đối tượng và hàm có thể thuộc vào định danh hoặc cấu trúc. Hơn nữa, chúng có thể khác nhau trong cùng một hệ thống phân kiểu (hầu hết các ngôn ngữ được liệt kê trước đây đều có cả hai).


Ví dụ, Flow sẽ sử dụng hệ thống định kiểu cấu trúc cho các đối tượnghàm, nhưng lại sử dụng dạng định danh cho các lớp.


Hàm:

4

Ở đây bạn có thể thấy một bí danh (alias) và một hàm có cùng đầu vào và đầu ra. Chúng có cùng cấu trúc và tương đương trong Flow.


Đối tượng:

5

Ở đây bạn có thể thấy một đối tượng sử dụng bí danh (alias) và một đối tượng thuần có cùng các thuộc tính, chỉ duy nhất các giá trị khác nhau: ‘string’ và ‘value’. Bởi vì ‘value’ thuộc vào kiểu ‘string’, nó là một kiểu con (đó là một kiểu cụ thể - string). Có nghĩa là đối tượng ‘obj’ của chúng ta là một kiểu con của ObjType.


Điều này không liên quan gì đến tên (lưu ý rằng không có gì nói rõ ràng rằng obj là một kiểu con của ObjType) và mọi thứ liên quan đến cấu trúc của cả hai. Vì các kiểu đối tượng trong Flow là covariant (nghĩa là chúng chấp nhận các kiểu con), điều này vượt qua bộ kiểm tra kiểu.


Lớp:

6

Ở đây bạn có thể thấy hai lớp giống nhau của chúng ta tạo ra lúc trước có cùng cấu trúc. Trong Flow thì không tương đương bởi Flow sử dụng kiểm tra kiểu định danh cho lớp.


Nếu bạn muốn sử dụng định kiểu dạng cấu trúc cho lớp bạn có thể sử dụng chúng bằng cách tận dụng các interface:

7

Các quyết định thiết kế trong Flow xoay quanh việc kết hợp giữa định kiểu dạng định danh và cấu trúc để tận dụng cho việc xác định kiểu cho đối tượng, hàm và các lớp trong Javascript. 


Ngôn ngữ Javascript đi theo ý tưởng kết hợp hai triết lý lập trình là hướng đối tượng và hướng chức năng lại với nhau. Các lớp (hoặc hàm tạo) thì có thiên hướng đi theo dạng hướng đối tượng nhiều hơn là hướng chức năng (như lambda). Và các đối tượng có xu hướng thiên nhiều hơn về lập trình hướng chức năng, các nhà phát triển sử dụng cả hai cùng một lúc. 


Các ngôn ngữ hướng đối tượng có khuynh hướng đi theo dạng phân loại kiểu dữ liệu định danh nhiều hơn (C ++, Java, Swift), trong khi các ngôn ngữ hướng chức năng có khuynh hướng sử dụng dạng cấu trúc (OCaml, Haskell, Elm).


Khi một ai đó viết ra một lớp, họ đang định nghĩa điều gì đó. Những thứ đó có thể có cấu trúc giống nhau nhưng lại được dùng cho những trường hợp khác nhau. Hãy tưởng tượng hai thành phần của các lớp đều có phương thức ‘render()’, nhưng cả hai bọn chúng đều có mục đích hoàn toàn khác nhau, nhưng trong hệ thống phân loại kiểu theo hướng cấu trúc thì lại được coi là tương đồng nhau.


Flow chọn những gì là tự nhiên nhất cho Javascript, và kết quả cuối cùng là một trải nghiệm tốt, điều mà bạn hằng mong đợi.


Hãy tiếp tục ủng hộ và giữ kết nối với Vnknowledge các bạn nhé:

  • Vnknowledge Page
  • Vnknowledge Youtube
  • Vnknowledge Patreon

Xin cảm ơn các bạn!

Từ khóa: 

vnknowledge

,

nodejs

,

js

,

javascript

,

typescript

,

lập trình