Elixir v1.20: giờ đây là một ngôn ngữ kiểu dần
(elixir-lang.org)- Suy luận kiểu và kiểm tra kiểu dần (gradual) được áp dụng cho mọi chương trình Elixir, giúp tìm ra mã chết và các lỗi đã được xác minh chắc chắn sẽ thất bại khi chạy ngay cả khi không có chú thích kiểu
- Kiểu
dynamic()khác vớiany()vốn “cho phép mọi thứ”: nó theo dõi phạm vi kiểu có thể có tại runtime và chỉ báo vi phạm khi hoàn toàn không chồng lấp với kiểu được cho phép - Giá trị
dynamic(integer() or binary())sẽ không tạo vi phạm với các lời gọi có phần khả năng chồng lấp, như phép toán số hoặc hàm chuỗi, nhưng sẽ tạo vi phạm với các lời gọi chỉ nhận map nhưMap.fetch! dynamic()được thu hẹp theo cách nó được sử dụng, tinh chỉnhdatatrong đoạn mã nhưdata.a + data.bthành một map có dạng%{..., a: number(), b: number()}- Trong guard, hệ thống suy luận hợp, giao và phủ định để dùng các điều kiện như
is_list,is_integer,is_map_key,not is_map_key,tuple_sizelàm thông tin kiểu casevà các câu lệnh điều kiện phản ánh thông tin của nhánh trước vào nhánh sau, thực hiện kiểm tra kiểu theo cách như xử lýniltrước rồi thu hẹp giá trị còn lại thànhbinary()- Kiểu đã được bổ sung cho nhiều hàm liên quan đến tuple và map trong thư viện chuẩn, giúp tìm ra các nhánh trùng lặp và mã chết trong codebase hiện có
- Trong “If T: Benchmark for Type Narrowing”, Elixir vượt qua 12 trong 13 hạng mục, cho thấy có thể khôi phục thông tin kiểu chính xác trong mã Elixir thông thường
- v1.20 cũng tiếp tục cải thiện thời gian biên dịch cho ứng dụng trong môi trường đa lõi, và trong benchmark tổng hợp, công cụ build của Elixir cho kết quả nhanh nhất среди các ngôn ngữ BEAM
- Tùy chọn compiler mới
:module_definitioncho phép chọn cách thực thi định nghĩa module với giá trị mặc định là:compiledhoặc:interpreted, và có thể bật bằngelixirc_options: [module_definition: :interpreted]trongmix.exs - Tùy chọn
:module_definitionkhông ảnh hưởng đến file.beamđược ghi ra đĩa mà chỉ thay đổi cách thực thi bên trongdefmodule, và có thể giúp cải thiện thời gian biên dịch trong các dự án lớn - Chữ ký kiểu mới sử dụng kiểu tập hợp sẽ được thảo luận cùng với định nghĩa typed struct sau khi hoàn tất nghiên cứu về hiệu năng hệ thống kiểu của v1.20, kiểu đệ quy, kiểu tham số hóa, và duyệt key-value của map
1 bình luận
Ý kiến trên Hacker News
Có thể chỉ là trải nghiệm cá nhân, nhưng có cảm giác nếu đó không phải là ngôn ngữ có type ngay từ đầu thì sẽ không hoạt động tốt bằng ngôn ngữ static type thực thụ
Tôi đã làm lập trình viên Elixir chuyên nghiệp khoảng 10 năm và đã mong chờ type từ lâu. Rất vui khi lần này bước khởi đầu đó đã thực sự xuất hiện
Tuy vậy, tôi muốn biết trạng thái hiện tại trong v1.20 so với Dialyzer không có đặc tả thì thế nào. Tôi hiểu cách tiếp cận success typing của Dialyzer gần giống kiểu “nếu có ít nhất một tổ hợp đối số chạy được thì không cảnh báo”, chứ không phải “nếu có tổ hợp đối số có thể thất bại thì cảnh báo”, và tôi cứ nghĩ Elixir lần này cũng làm điều gì đó tương tự, còn Dialyzer thì tôi không thấy hữu ích lắm
Tôi đã thấy vài bài trên HN về hệ thống gradual typing của Elixir nhưng chưa theo dõi kỹ. Tôi muốn hỏi có ai biết liệu hệ thống gradual typing này có thể thay đổi độ phức tạp tiệm cận của chương trình so với mã không có type hay không
Theo tôi biết, phần lớn các hệ thống gradual typing, ví dụ như Racket, có thể làm chương trình chậm hơn về mặt tiệm cận, dù cũng có một số ngoại lệ [1]
[1] https://doi.org/10.1145/3314221.3314627
Hầu hết các hệ thống gradual typing đều chèn ép buộc khi giá trị đi qua ranh giới giữa mã có type và không có type. Ví dụ như kiểm tra mọi phần tử trong danh sách, hoặc bọc giá trị bằng type proxy. Nhưng nhóm Elixir đã công bố kết quả strong arrows để đạt được tính soundness mà không cần các kiểm tra runtime như vậy, và bytecode mà compiler tạo ra giống hệt mã không có type về mặt ngữ nghĩa
Trớ trêu là các nhà phê bình nói rằng type là cần thiết, còn fan Elixir thì nói không cần type và Elixir bằng cách nào đó rất thần kỳ nên không phát sinh lỗi liên quan đến type, giờ thêm type vào thì lại tìm ra bug. Chẳng phải trước đó họ nói không cần để ngăn bug sao? Dù vậy đây vẫn là thay đổi tốt. Trước đây tôi đã dùng Elixir khá nhiều và rất thích, nhưng thật khó để đồng tình với việc thiếu type
https://en.wiktionary.org/wiki/Goomba_fallacy
Tôi không đồng ý với góc nhìn đó, nhưng đó là lập luận dễ bảo vệ hơn nhiều so với kiểu “$LANGUAGE là phép màu”
Trước khi lý thuyết kiểu tập hợp phát triển, có lẽ đó còn là một lập trường đúng
Rồi cuối cùng họ vẫn thêm static typing. Điều đó đã xảy ra với Python, JavaScript, Ruby, và chắc còn nữa
Tôi rất thích việc có thể cập nhật Elixir mà không gặp thay đổi phá vỡ tương thích trong nhiều dự án, và compiler còn tìm bug miễn phí cho mình. Tôi đã quá quen với điều đó rồi
Nhìn thấy điều này tôi thực sự rất vui. Giờ nó đang tiến gần hơn tới mức “một ngôn ngữ tuyệt vời”, và với tôi Elixir là ứng viên số một
Nếu có ngôn ngữ nào khác cũng dễ dùng như vậy mà vẫn tiếp tục bổ sung các tính năng tuyệt vời theo cách ổn định và an toàn, tôi rất muốn được giới thiệu. Tôi đã từng thành thạo Go rồi chuyển sang học C# nâng cao, nhưng tôi có cảm giác Go đã ngừng bổ sung các tính năng hay
Trong tháng vừa qua tôi đã thử làm track Elixir trên exercism.io https://exercism.org/tracks/elixir
Thật sự rất tuyệt
À, lại bắt đầu rồi. Có vẻ tôi sẽ lại học Elixir thêm 1 năm nữa
Tôi thích mọi thứ ở Elixir, nhưng hơn bất kỳ ngôn ngữ nào khác, Elixir luôn khiến tôi tiếp tục nghi ngờ chính mình. Có lẽ não tôi không hợp với kiểu hàm, nhưng thay đổi này khiến tôi muốn thử lại
Điều đáng tiếc là hệ sinh thái khó mà xem là thân thiện với người mới bắt đầu, và khi trả lời câu hỏi thì người ta thường mặc định là bạn đã biết khá nhiều về ngôn ngữ rồi
Đừng để tiêu đề đánh lừa. Nửa đầu cuốn sách đơn giản chỉ là Elixir
Trong 8 năm qua, mỗi lần tôi cần làm quen lại với Elixir thì tôi lại dùng cuốn sách này, và lần nào cũng hiệu quả. Tôi chưa từng đọc hết
Một trong những tiêu chí để đánh giá sách lập trình kiểu dự án hướng dẫn như thế này có tốt hay không là: dù đã bắt đầu nhiều lần mà chưa đi đến cuối, liệu đến khoảng giữa sách bạn đã có đủ công cụ để quay lại làm việc của mình hay chưa
Nhưng tôi nghĩ không phải vì não không hợp, mà là vì sự tương phản giữa mức kinh nghiệm tích lũy trong các ngôn ngữ mệnh lệnh và việc phải bắt đầu lại như người mới trong phong cách thuần hàm
Rồi sẽ dần khá lên thôi. Bước ngoặt để tôi thấy thoải mái với lập trình hàm là khi nhận ra mình thích việc ghép các đoạn code kiểu Bash “one-liner” được giãn cách thoáng ra đến mức nào. Dữ liệu bắt đầu ở một dạng nào đó, tôi đổ nó ra bằng một lệnh, nghĩ xem bước nào sẽ đưa nó gần hơn tới dạng mình muốn, rồi pipe sang lệnh tiếp theo và xem lại. Cứ thế tiếp tục, đến cuối cùng thường còn lại một chuỗi các phép biến đổi dữ liệu mà không thay đổi dữ liệu tại chỗ
Một phần lý do cách này thấy dễ chịu trong shell là vì ngày nào bạn cũng đi qua lại trong hệ thống tệp và tích lũy dần vốn từ lệnh. Thư viện “hàm” quen thuộc của tôi trong môi trường kiểu Unix đã lớn lên đáng kể qua nhiều năm. Trong môi trường lập trình thuần hàm, bạn cũng phải làm điều tương tự, chỉ là việc học vốn từ cần thêm chút công sức. Các “lệnh” thường dùng sẽ là những hàm như map, fold, zip thay vì grep, cat, sort
Nhưng cốt lõi thực sự là như nhau, và sức hấp dẫn của việc tạo pipeline cũng áp dụng giống hệt ở cả hai bên. Bạn có thể xây từng mảnh một, và với mỗi câu đố nhỏ, bạn quên bước trước đi rồi chỉ nghĩ xem dữ liệu trước mắt cần được biến đổi thế nào ở bước tiếp theo. Mức yêu cầu ngữ cảnh thấp này vừa mới mẻ vừa dễ chịu
Chúc bạn nhất định sẽ thử và thấy thích. Khi bạn học được cách tận hưởng trạng thái mình chưa làm được điều gì đó, đó cũng là lúc cuối cùng bạn sẽ làm tốt nó
Tất nhiên tôi mới chỉ nghịch vài buổi chiều thôi, nhưng nếu tôi định lại rèn não mình theo hướng ngôn ngữ hàm, thì vì sự quen thuộc tôi có lẽ sẽ chọn Gleam
Đôi khi có những bài mơ hồ nên không thu hút được chú ý, hoặc bị phớt lờ vì có mùi kiểu “làm hộ bài tập cho tôi”
Nhưng các bài viết thể hiện sự tò mò thật sự thì theo tôi thấy đều nhận được câu trả lời
Tuyệt vời. Có vẻ ở 1.20, việc biên dịch ứng dụng umbrella lớn của chúng tôi đã nhanh hơn khá nhiều
Tôi tò mò không biết so với Gleam thì thế nào. Hay là giờ tại sao vẫn nên dùng Elixir thay vì Gleam? Có lẽ Phoenix, đặc biệt là LiveView, là sức hút lớn của Elixir
Tôi không rõ trạng thái hiện tại của Gleam OTP, nhưng lần cuối tôi xem thì nó chưa ổn lắm
Nếu cả hai điều đó đều không quan trọng với bạn và thứ duy nhất bạn quan tâm là type, thì cứ dùng Gleam. Nhưng vậy thì chẳng phải dùng Rust luôn sẽ hợp lý hơn sao?
Ví dụ, ở Gleam thì việc decode/encode JSON có thể trở nên dài dòng. Trong Rust bạn chỉ cần derive serde, còn trong Elixir thì chỉ cần một lời gọi hàm
Elixir có hệ sinh thái trưởng thành hơn. Ví dụ ở Gleam bạn có thể dùng Phoenix hoặc các framework Gleam khác, nhưng trải nghiệm sẽ không giống nhau
Lý do lớn nhất khiến Gleam hấp dẫn hơn Elixir là type, và giờ Elixir đang thu hẹp khoảng cách đó. Một điểm nữa là có thể compile sang JavaScript, còn bên Elixir thì Hologram đang làm điều gì đó tương tự
Cá nhân tôi thích hệ thống type của Gleam và cú pháp kiểu Rust hơn, nhưng hiện tại tôi vẫn thấy Elixir là lựa chọn tốt hơn cho mọi dự án phát triển web của mình