Strong vs Weak, Static vs Dynamic typing là cái khỉ gì?
This post hasn't been updated for 7 years
Bạn có thể xem bài viết gốc tại vuonghv.github.com
Trên con đường đến với đạo lập trình, chắc các bạn cũng từng nghe đến các khái
niệm như strong/weak
typing, static/dynamic
typing. Bạn có bao giờ thắc mắc
chúng có nghĩa là gì? và các ngôn ngữ thông dụng như Java, C/C++, Python,
Javascript, ... là strong hay weak typing? static hay dynamic typing?
Hơn nữa, nhiều người vẫn đang nhầm tưởng rằng static đồng nghĩa với strong typing và dynamic đồng nghĩa với weak typing. Vậy bạn hãy cùng tôi dạo qua bài viết này để có một cái nhìn cụ thể hơn.
Strong vs Weak typing
Hiện tại thì người ta vẫn chưa thống nhất một định nghĩa chuẩn thế nào là một ngôn ngữ strong typing hay weak typing. Và đây cũng là một chủ đề gây ra rất nhiều tranh luận mỗi khi có ai đó nêu ra. Ở đây tôi muốn nêu ra khái niệm được nhiều người chấp nhận và theo tôi thấy thì cũng ngắn gọn và dễ hiểu nhất:
Strong typing means that the type of a value doesn't suddenly change.
Theo đó, các ngôn ngữ strong typing đảm bảo rằng kiểu (types) của một object không thay đổi một cách đột ngột, không tường minh. Hay nói cách khác, ta phải chỉ rõ thao tác (thông qua lời gọi hàm, ép kiểu, ...) khi muốn chuyển đổi kiểu của một object.
Những ngôn ngữ không đáp ứng yêu cầu trên là weak typing.
Nói nhiều quá, lấy một số ví dụ cho dễ hiểu nào?
Xét đoạn code PHP sau:
$a = "3" + "5"; // $a === 8
$b = 101 . " dogs"; // $b === "101 dogs"
Ta thấy ở câu lệnh trên, kiểu của string "3"
và "5"
đã tự động chuyển thành
số nguyên 3
và 5
, dẫn đến giá trị của biến $a
là 8
. Tương tự, số nguyên
101
đã ngầm định chuyển thành string "101"
. Do đó PHP là một ngôn ngữ weak
typing.
Tương tự, Javascript cũng là ngôn ngữ weak typing:
let a = "abc" + 123; // 123 is implicitly converted to string "123"
console.log(a); // "abc123"
Trái lại, ta cùng xem đoạn code Python dưới đây:
>>> "abc" + 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> "abc" + str(3)
'abc3'
Ta thấy rằng, khi cố gắng thực hiện phép toán cộng giữa một object string và một
số nguyên, trình thông dịch Python sẽ thông báo lỗi TypeError
bởi vì ta không
được phép ngầm định chuyển đổi object kiểu int sang kiểu string. Thay vào đó,
ta phải chỉ rõ tưòng minh thao tác chuyển đổi kiểu thông qua hàm str()
.
Nếu không quá khắt khe thì ta có thể coi Python là ngôn ngữ strong typing, bởi
vì Python vẫn có một số ngoại lệ, ví dụ như biểu thức 1.0 + 2
sẽ cho ra giá
trị là số thực 3.0
(số nguyên 2
đã tự động chuyển sang kiểu số thực).
Với strong typing, chương trình của chúng ta sẽ rõ ràng, dễ debug và kiểm soát
hơn so với weak typing. Bất cứ khi nào ta thực hiện một thao tác với các đối
tượng có kiểu không tương thích nhau, chương trình sẽ xuất ra một thông báo
lỗi sai kiểu (chẳng hạn TypeError
exception trong Python). Chúng ta không
cần phải nhớ một đống quy tắc tự động chuyển đổi kiểu trong các phép toán cơ
bản ( ví dụ như, khi nào thì string sẽ tự động chuyển sang kiểu số, và ngược
lại, ...) và hơn nữa, rất khó để debug khi biến âm thầm đổi kiểu mà
ta không biết.
Static vs Dynamic typing
Trong các ngôn ngữ static typing (C/C++, Java), mỗi biến (variable) có một kiểu cố định liên kết với nó. Kiểu của biến được kiểm tra lúc compiled-time và trình biên dịch yêu cầu ta phải khai báo rõ kiểu của biến trước khi sử dụng.
Ví dụ về khai báo biến trong C:
int a; // the type of a is integer
a = 3; // OK, assign 3 to a
a = "Hello"; // Error, cannot assign string value to int
Nếu ta đã khai báo một biến có kiểu nguyên, ta sẽ không thể gán các giá trị có kiểu khác tới nó.
Trái lại, với dynamic typing, mỗi biến chỉ đơn giản là một cái nhãn (label)
được liên kết với một object. Mỗi object sẽ có kiểu riêng của nó (ví dụ trong
Python, ta có kiểu int, str, list, dict, ...
) nhưng bản thân biến thì không.
Và kiểu của biến hay nói chính xác hơn là kiểu của object liên kết với biến được
kiểm tra lúc runtime.
Dynamic typing trong Python:
b = 3 # variable b is bound to integer object
isinstance(b, int) # True
b = 'hello world!' # Now b is bound to string object
isinstance(b, str) # True
b = ['blue', 'black', 'brown'] # Now b is a list
Tuy rằng có thể gán các object có kiểu khác nhau cho cùng một biến trong các ngôn ngữ dynamic typing nhưng việc đấy được xem như bad practice trong coding. Bởi vì việc thay đổi kiểu của biến tùy tiện sẽ làm cho code của chương trình rất khó đọc và khó debug.
Nghe cũng thú vị đấy, nói nghe ưu nhược điểm của từng loại xem nào?
Dưới đây là so sánh ưu nhược điểm của static với dynamic typing theo một số tiêu chí phổ biến:
-
Ngắn gọn: Với dynamic typing, code trông sẽ ngắn gọn hơn bởi vì nó bỏ đi các khai báo kiểu cho biến, tham số cũng như giá trị trả về của hàm.
-
Tài liệu: Với tiêu chí này thì static typing lại chiếm ưu thế hơn, khi khai báo kiểu cho biến, tham số,... bản thân nó cũng đã phục vụ như bản đặc tả tài liệu. Hơn nữa static typing giúp tính năng intelligent completion trong IDE làm việc tốt hơn. Gần đây Python (version 3.5) có type hints và Microsoft đẻ ra thằng typescript cũng có một phần vì lý do này.
-
Tính đúng đắn: Trong một ngôn ngữ static typing, những lỗi về kiểu (type errors) có thể được phát hiện tại thời điểm compile vì vậy chương trình sẽ an toàn và ít lỗi hơn so với dynamic typing, do lỗi về kiểu chỉ có thể phát hiện lúc chạy chương trình.
-
Hiệu năng: Trong ngôn ngữ dynamic typing, do phải mất chi phí để kiểm tra kiểu lúc runtime nên hiệu năng sẽ giảm đi đáng kể. Trái lại, static typing cho phép compiler thực hiện một số tối ưu lúc biên dịch chương trình do kiểu của biến đã được khai báo trước.
Kết luận
Phần này chỉ đơn giản là tóm tắt lại những gì được nói ở trên.
Strong typing đảm bảo rằng kiểu của một object không tự động thay đổi, hay nói cách khác là không thay đổi một cách ngầm định. Trong khi đó, với static typing, một biến chỉ có một kiểu duy nhất và phải được khai báo trước khi sử dụng, kiểu của biến được kiểm tra tại thời điểm biên dịch chương trình.
Với weak typing, kiểu của một object có thể tự động thay đổi (cái này Tây họ gọi là "implicit conversions"). Trong khi đó, với các ngôn ngữ dynamic typing, ta có thể gán các object có kiểu khác nhau cho cùng một biến và kiểu của object gắn liền với biến được kiểm tra lúc chạy chương trình.
Qua bài viết, hi vọng bạn đã có thêm một số kiến thức cũng như biết được sự khác nhau giữa các hệ thống kiểu (typed system) trong ngôn ngữ lập trình.
Rất mong nhận được sự góp ý cũng như thảo luận từ các bạn!
Nguồn tham khảo:
- Why is Python a dynamic language and also a strongly typed language
- Is Python strongly typed?
- The difference between a strongly and a statically typed language?
_EOF_
All Rights Reserved