Nếu viết lại Rust
(josephg.com)- Rust khởi đầu từ một nhận thức vấn đề: dù có an toàn bộ nhớ, hiệu năng, kiểu đại số và các lợi thế của Cargo, quá trình tiến hóa ngôn ngữ trên kênh stable đã chậm lại, khiến nó có cảm giác như “một sản phẩm thế hệ đầu vẫn chưa hoàn thiện”
- Sau khi cộng đồng lớn lên, ra quyết định dựa trên đồng thuận trở thành nút thắt; các tính năng như coroutine dù đã được triển khai nhưng vẫn không thể dùng trong stable Rust trong thời gian dài tiếp tục tích tụ
- “seph edition” giả định là một ý tưởng cho phép breaking change trong khi vẫn duy trì Rust hiện có và hệ sinh thái Cargo, nhằm thử nghiệm hệ thống effect, quyền ở thời điểm biên dịch, borrow trường struct, comptime, v.v.
- Để giảm rủi ro chuỗi cung ứng, cần gắn capability cho các tính năng nhạy cảm như ghi file, mạng, FFI,
unsafe, và bên gọi phải cho phép rõ ràng - Phần lớn đề xuất không tương thích với Rust hiện tại; chỉ riêng việc thêm capability cũng tạo ra điều kiện thất bại mới phá vỡ tương thích semver, nên cần một edition mới hoặc fork compiler
Vì sao Rust có cảm giác như “sản phẩm thế hệ đầu”
- Ban đầu Rust là một ngôn ngữ rất hấp dẫn nhờ kiểu đại số, an toàn bộ nhớ không đánh đổi hiệu năng, và trình quản lý package hiện đại
- Sau khoảng 4 năm sử dụng, ngôn ngữ này có cảm giác như luôn ở trạng thái “còn thiếu một chút”
- Điểm bất mãn cốt lõi là tần suất tính năng mới đi vào stable Rust đã giảm, và tốc độ tiến hóa của ngôn ngữ cũng chậm đi đáng kể
- Rust unstable book có khoảng 700 unstable feature, trong đó nhiều mục là thay đổi ở thư viện chuẩn
- Coroutines là tính năng có RFC đã 7 năm tuổi và đã được triển khai trong compiler, nhưng người dùng stable Rust vẫn chưa thể dùng
- Quy trình RFC của Rust trông giống như một nơi các ý tưởng hay bị lưu lại quá lâu
- Cuộc thảo luận cải tiến
Mutexđược nêu như một ví dụ: 25 người để lại hơn 200 bình luận trong 2 năm nhưng không đi đến kết luận rõ ràng
- Cuộc thảo luận cải tiến
Ý tưởng “seph edition” giả định
- Có thể tưởng tượng một cách làm là fork compiler nhưng giữ nguyên code Rust hiện có, đồng thời thêm “seph” như một Rust edition riêng
- Trong edition này, có thể cho phép breaking change, nhưng nếu compiler vẫn biên dịch được mainline Rust thì vẫn có thể tiếp tục dùng các crate hiện có của Cargo
- Có năm trục lớn muốn thay đổi
- Function trait và hệ thống effect
- Capability ở thời điểm biên dịch
- Thiết kế lại
Pin, move và borrow struct comptimekiểu Zig- Các cải tiến nhỏ về cú pháp và thư viện chuẩn
Function trait và hệ thống effect
- Rust có trait cho struct, nhưng đề xuất cho rằng cũng cần có thể gắn trait/effect phong phú hơn cho function
- Các thuộc tính mà một function có thể có được tóm lược như sau
- Có thể panic hay không
- Kích thước stack có cố định hay không
- Có chạy đến hết hay thực hiện
yieldhoặcawaithay không - Kiểu continuation khi là coroutine
- Có phải pure function hay không
- Có gián tiếp thực thi code
unsafehay không - Có đảm bảo kết thúc hay không
- Nếu phơi bày parameter và kiểu trả về của function như associated type của function, có thể tham chiếu kiểu theo cách hiện không thể làm trong stable Rust
- Ví dụ là code đặt tên trực tiếp kiểu trả về của function như
some_iter::Outputrồi đưa vào field của struct - Khi cần bảo đảm rằng một khối code nhất định tuyệt đối không panic, như trong Linux kernel, có thể dùng đánh dấu như
#[disallow(Panic)]để kiểm tra khả năng panic bao gồm cả các lời gọi đệ quy - Compiler hiện đã xử lý các trait liên quan đến function như
Fn,FnOnce,FnMut, nhưng dạng hiện tại bị đánh giá là quá nghèo nàn - Tài liệu tham khảo chi tiết hơn được liên kết tới bài viết và bài nói về effect system của Yoshua Wuyts
Giảm rủi ro chuỗi cung ứng bằng capability ở thời điểm biên dịch
- Phần lớn dự án Rust kéo vào nhiều crate bên thứ ba, và ngay cả crate tiện ích nhỏ cũng có thể tạo rủi ro chuỗi cung ứng thông qua bản cập nhật độc hại
- Cũng như
unsafelà opt-in rõ ràng trong an toàn bộ nhớ, các tính năng nhạy cảm liên quan đến hệ thống file, mạng, FFI và raw pointer cũng nên phải được cho phép rõ ràng - Đề xuất là gắn marker tag cho các function nhạy cảm về bảo mật trong thư viện chuẩn
- Ví dụ:
std::fs::write(path, contents)ghi file vào đường dẫn tùy ý nên có tag như#[cap(fs_write)] - Compiler tự động taint toàn bộ call tree gọi function đó
- Ví dụ:
- Nếu crate bên thứ ba cần capability
fs_write, bên gọi phải cho phép rõ ràng trongCargo.tomlhoặc bằng annotation tại điểm gọi - Nếu không cho phép, compiler có thể báo lỗi rằng
foo::do_stuff()ghi vào hệ thống file cục bộ nhưng cratefoochưa được tin cậy với capability đó - Nhiều crate tiện ích như
human-sizehayserdekhông cần capability đặc biệt, nên ngay cả khi tác giả thêm code độc hại, hành vi ghi file hoặc truy cập mạng có thể bị chặn ở bước biên dịch - Một phương án thay thế là đổi API nhạy cảm để nhận một parameter
Capabilityriêng- Ví dụ:
std::fs::writeyêu cầu một giá trịFsWriteCapability - Việc tạo object
Capabilitybị giới hạn chỉ cho root crate
- Ví dụ:
- Cách này tăng boilerplate nhưng linh hoạt hơn, và cũng cần xử lý tương tự với script
build.rsvà blockunsafe - Ngay cả trong tình huống crates.io bị hack và code cryptolocker được đưa vào
serde, với cách dùng capability, lỗi biên dịch sẽ xảy ra trước khi code đó chạy trên máy của nhiều developer hoặc được đưa vào binary
Thiết kế lại Pin, move và borrow struct
Pinbị đánh giá là một hack phức tạp để đi vòng qua lỗ hổng của borrow checker, một band-aid sinh ra từ nỗ lực giữ tương thích ngược- Thứ thực sự cần được xem là gần với
Movemarker trait để đánh dấu các kiểu có thể di chuyển - Rust hiện không có trait
Pinmà cóUnpinvà!Unpin; dạng phủ định kép này khiến khái niệm khó hiểu hơn - Có phê bình rằng vì
Pinchỉ áp dụng cho kiểu tham chiếu, code bọc bằngBoxxuất hiện khắp nơi- Ví dụ có liên kết tới các helper library như Tokio stream wrapper,
ouroboros,async-trait,self_cell
- Ví dụ có liên kết tới các helper library như Tokio stream wrapper,
- Các function nhận giá trị pinned như
Future::poll(self: Pin<&mut Self>, ..)cũng trở nên phức tạp, và cần crate riêng để xử lý projection - Bên trong function, borrow checker quản lý biến ở các trạng thái “owned”, “borrowed”, “mutably borrowed”, nhưng các trạng thái này không trực tiếp hiển thị với programmer
- Với
async fn, compiler tạo hidden struct để lưu trạng thái tạm dừng, và khi đó có thể xuất hiện dạng một field borrow field khác - Rust không có cú pháp để biểu diễn rằng field của struct đang ở trạng thái borrowed, cũng không thể biểu diễn trực tiếp lifetime giữa các field
- Hướng đề xuất là mở rộng borrow checker để có thể viết trực tiếp borrow trường struct
- Ví dụ: cú pháp “local borrow” như
y: &'Self::x Vec<usize> - Compiler biết rằng
xđã bị borrow và áp dụng các ràng buộc giống như với biến borrowed bên trong function
- Ví dụ: cú pháp “local borrow” như
- Cú pháp như vậy cũng có thể dùng để xử lý self-referential struct hoặc các dạng như
source: Stringvàast_nodes: Vec<&'Self::source str>trong AST - Struct có borrowed field sẽ không thể di chuyển nên sẽ không implement
Move; xa hơn nữa cũng có thể cân nhắc traitMoverđể tự di chuyển một cách an toàn
comptime kiểu Zig và vấn đề macro của Rust
- Rust compiler về bản chất trông như một cấu trúc xử lý cùng lúc nhiều ngôn ngữ: Rust, ngôn ngữ Rust macro và cả proc macro
- Điểm chính của đánh giá là bản thân Rust tốt, nhưng ngôn ngữ macro thì không tốt
- comptime của Zig là cách compiler chạy một phần code ở thời điểm biên dịch thông qua một interpreter nhỏ
- Function, parameter,
if, loop có thể được đánh dấu là code thời điểm biên dịch, còn code non-comptime được emit vào chương trình thực std printcase study của Zig là ví dụ nhận format string làm parameter comptime, rồi phân tích cú pháp trong vòng lặpcomptimeđể sinh code in ra- Việc triển khai
println!()của Rust gọi các function nội bộ nhưformat_args_nl, và function này được cho là hard-code trong compiler - Phê bình tiếp theo là trông như ngay cả tác giả Rust compiler cũng không muốn dùng ngôn ngữ macro của Rust
Các chỉnh sửa nhỏ về cú pháp và thư viện chuẩn
- Có một mục muốn sửa vấn đề
Range<T>implementCopykhiT: Copy - Vấn đề derive khi có associated type cũng được liệt kê là đối tượng cần sửa
- Issue liên quan: derive with associated types
- Ví dụ: Playground
- Có đề xuất rằng biểu thức
if letnên hỗ trợ logical AND- Dạng mong muốn:
if let Some(x) = some_var && some_expr { } - Cách đi vòng hiện tại là match tuple
(some_var, check_foo()), nhưng ngay cả khisome_varlàNone,check_foo()vẫn chạy, khác với hành vi short-circuit củaifthông thường - Ví dụ: Playground
- Dạng mong muốn:
- Ergonomics của raw pointer cũng được nêu là mục cần cải thiện
- Với tham chiếu có thể viết
myref.x, nhưng với pointer phải viết như(*myptr).xhoặc(*(*myptr).p).y - Quan điểm là code
unsafenên dễ đọc và dễ viết nhất có thể
- Với tham chiếu có thể viết
- Có đề xuất muốn đổi các built-in collection type để nhận rõ
Allocatortrong constructor thay vì dùng global allocator asynccũng cần cải thiện, nhưng phần này được để lại vì có quá nhiều nội dung, đủ để cần một bài riêng
Tương thích và khả năng thực thi
- Phần lớn đề xuất không tương thích với Rust hiện tại
- Ngay cả việc thêm security capability cũng tạo ra một kiểu điều kiện thất bại mới khiến crate phá vỡ tương thích semver, nên cần một Rust edition mới
- Nếu là vài năm trước, có lẽ tác giả đã viết RFC, nhưng muốn tránh tình huống trải qua quy trình bình luận RFC dài trên GitHub rồi lại trở thành một ý tưởng nữa không được hiện thực hóa
- Cuối cùng ý tưởng quay lại với việc tự fork compiler, nhưng vẫn còn ràng buộc thực tế là có quá nhiều dự án cần làm
1 bình luận
Ý kiến trên Hacker News
Trái với nhận định rằng quy trình RFC của Rust là nghĩa địa của những ý tưởng hay, tôi cho rằng việc đội ngũ cốt lõi Rust khiến việc thêm tính năng mới vào ngôn ngữ lập trình trở nên khó khăn là hướng đi đúng
Cần ngăn bề mặt ngôn ngữ trở nên phình to, thiếu nhất quán và khó dự đoán. Ban đầu tôi cũng thích Swift, nhưng rồi cuối cùng đã bỏ cuộc khi những thứ như tên hàm trùng lặp kiểu
isMultiple(of:), quy tắc phân tích cú pháp dấu ngoặc nhọn dành cho SwiftUI, các quy tắc về kiểu tham chiếu/kiểu giá trị và tính khả biến, cách viết tắt tham số closure, v.v. cứ tiếp tục tăng lên. Ý tưởng hay thì rất nhiều, nên tôi mong Rust được giữ gọn nhẹ hết mức có thểVí dụ, ta có thể dùng hàm trả về
impl Traitvà struct có thể có các trường tùy ý, nhưng lại không thể đưa giá trị được trả về bằngimpl Traitvào trường của struct. Lý do là không thể đặt tên cho kiểu đó.if a && bthì được,if let Some(x) = xcũng được, nhưngif let Some(x) = x && bthì không. Tôi mong những thứ như vậy được sửa. Tính theo số dòng mã của compiler thì Rust sẽ lớn hơn, nhưng xét theo độ phức tạp khi học và sử dụng, các lỗ hổng tính năng như thế lại khiến ngôn ngữ phức tạp hơn.Pinkhông phải là một việc quá lớn để triển khai trong thư viện chuẩn, nhưng tuyệt đối không phải là một tính năng gọn nhẹ, và gánh nặng nhận thức của nó là rất lớn. Tôi cho rằng một borrow checker phức tạp và mã Rust dễ đọc vẫn tốt hơn một compiler đơn giản nhưng ngôn ngữ khó dùngNgay cả nếu 100% ý tưởng đang chờ đều được chấp nhận và cuối cùng được thực hiện, nó vẫn sẽ trông như vậy vì chênh lệch giữa tốc độ đi vào và tốc độ đi ra. Nếu muốn đi trước các tác giả RFC, tốt hơn là đừng viết RFC; hãy tạo một bản triển khai sẵn sàng cho production kèm tài liệu và kiểm thử, có thể được merge sạch sẽ vào tree
Không thể dùng làm const generic của kiểu khác, cũng không thể dùng làm độ dài mảng. Nếu chỉ cần một giá trị thì có thể định nghĩa hàm để trả về, nên hiện tại nó không hữu ích lắm. Nếu được hỗ trợ đúng cách, có thể loại bỏ các crate phụ trợ như
generic_array,typenumtrong thư viện mật mã. Dù vậy, tôi vẫn đồng ý rằng đội ngũ Rust cần thận trọng khi thêm tính năngTình hình phụ thuộc khá nghiêm trọng, nhưng có vẻ không nhiều người muốn thừa nhận. Ví dụ tôi thấy gần đây là crate cargo-watch
Về cốt lõi, đây là một ứng dụng đơn giản theo dõi thay đổi tệp và chạy lại trình biên dịch, phần triển khai chưa đến 1.000 dòng. Thế nhưng nếu vendor các phụ thuộc vào, mã Rust phình lên gần 4 triệu dòng, trải trên hơn 8.000 tệp. Như vậy là quá mức đối với một trình theo dõi tệp đơn giản
https://crates.io/crates/cargo-watch
C/C++ gần như là trường hợp duy nhất trong các ngôn ngữ phổ biến mà trình quản lý gói kiểu npm không trở nên đại chúng, nên đa số thư viện thường tự hoàn chỉnh, hoặc có ít phụ thuộc và các phụ thuộc đó thường là tùy chọn.
efswlà một trình theo dõi hệ thống tệp C++ dài 7.000 dòng, không có phụ thuộc. Các thư viện single-header trong mảng lập trình game nhưstb_*,cgltf, và Dear ImGui là những thứ dễ chịu nhất tôi từng dùng. Tôi cho rằng với trình quản lý gói mới, cấm phụ thuộc bắc cầu nhìn chung có thể có lợi. Các phụ thuộc thư viện lớn có thể để người dùng tự cài, cung cấp callback, hoặc biến thành tính năng chuẩnhttps://github.com/SpartanJ/efsw
https://github.com/nothings/stb
https://github.com/jkuhlmann/cgltf
https://github.com/ocornut/imgui
Riêng trình theo dõi tệp thì tôi nghĩ không hề đơn giản, nhất là khi hỗ trợ nhiều nền tảng
Một phần của
cargo watchkéo vào thư viện wrapper cho Win32 API; đó là các binding được tạo tự động cho lời gọi Win32, nên tất yếu rất lớn. Thư viện chuẩn của hầu hết ngôn ngữ cũng có hàng triệu dòng, và ứng dụng chỉ dùng một phần trong đó. Boost của C++ cũng to như quái vật, nhưng lập trình viên chỉ lấy vài phần mở rộng để dùng. Thay vì địa ngục kiểu npm, nơi một gói nhưisOddhayis evencũng có thể làm hỏng cả hệ sinh thái, thì ít phụ thuộc lớn hơn, được nhiều người duy trì và dựa vào, vẫn tốt hơn; Rust nhìn chung gần với hướng đó hơnPhần lớn phụ thuộc của
cargo-watchdường như đến từ ba yêu cầu trực tiếp làclap,cargo_metadata,watchexec.clapkéo vào nhiều thành phần CLI theo từng nền tảng, còncargo_metadatagần như bắt buộc phải kéo theo nhiều thứ thuộc hệserde.watchexecthì có chỗ để cải thiện: nó phụ thuộc vàocommand-group, cũng do cùng tổ chức quản lý, và gói này lại bắt buộc cần Tokio. Vấn đề lớn hơn là rất khó sửa phụ thuộc quá mức của các crate khác. Nếu có crate bị trói vào mộtwatchexeccũ, đôi khi có thể khớp bằng cách chỉnhCargo.lock, nhưng thường thì khó và phải lách bằng[patch]. Sẽ tốt nếu có cách dễ dàng định nghĩa một “stand-in” thay thế cho một crate ở phiên bản cụ thể, nhưng với các trình quản lý gói hiện có thì đây có vẻ là một bài toán nghiên cứu lớnRust không còn là một ngôn ngữ non trẻ thú vị nữa, mà đang ở giai đoạn hướng tới được áp dụng rộng rãi. Việc phát triển tính năng chậm lại là điều tự nhiên và lành mạnh
Lúc này, sai lầm thiết kế gây hại hơn nhiều so với tốc độ thấp. Rust thú vị không phải vì các tính năng hào nhoáng, mà vì nó là một lớp ngôn ngữ mới: an toàn bộ nhớ, không có garbage collection và sẵn sàng cho production. Việc nó thực sự được đưa vào những nơi quan trọng còn thú vị hơn việc làm cho ngôn ngữ tốt hơn, và điều đó sẽ dễ hơn nếu có niềm tin rằng nó được vận hành một cách thận trọng
Spread operator, generator function,
async, arrow function,leftpad,Datemới, danh sách các tính năng quan trọng là không có hồi kết. JS lâu đời hơn Rust rất nhiều, được dùng rộng rãi hơn rất nhiều, và có nhiều triển khai production nên mọi tính năng mới đều phải được triển khai khớp nhau. Đã từng có một giai đoạn trì trệ quanh ES5, nhưng khác biệt có vẻ nằm ở việc ủy ban tiêu chuẩn ECMAScript đã tỉnh táo lạiVì các Rustacean có vẻ ám ảnh với việc viết lại mọi thứ bằng Rust, tôi thật sự đã nghĩ rằng một bài viết về viết lại Rust hẳn sẽ là một trò đùa châm biếm meta
Việc trước hết phàn nàn về quá trình ra quyết định chậm, rồi lại liệt kê các tính năng có lý do chưa ổn định hóa gần như không liên quan đến ra quyết định, có vẻ hơi lạ
Ví dụ, coroutine đang bị kẹt vì có những trường hợp biên khó giải quyết cho đúng. Không phải trong compiler đã có một bản triển khai hoàn chỉnh “chỉ cần bật lên” là xong, mà là một bản triển khai chưa hoàn thiện, hoạt động trong nhiều trường hợp nhưng không thể bật trên bản ổn định. Function trait cũng đã được quyết định rõ ràng là sẽ không ổn định hóa ở hình thức hiện tại vì nhiều lý do kỹ thuật và do tương tác với các tính năng trong tương lai. Nếu quay về quá khứ có lẽ có những phần đã được thiết kế khác đi, nhưng phần lớn liên quan đến các quyết định từ thời kỳ đầu của Rust, khi đội ngũ và nguồn lực còn nhỏ hơn rất nhiều. Có thể có quan điểm rằng vì bây giờ ta có thể chọn tốt hơn nên nên tạo một kiểu đứt gãy như Rust 2.0, nhưng vì thảm họa chuyển từ Python 2 sang 3 quá lớn, nhiều người cho rằng chịu đựng các góc cạnh thô ráp vẫn tốt hơn. Nếu xem newsletter hằng tuần của Rust, các quyết định phê duyệt RFC và ổn định hóa vẫn được xử lý mỗi tuần. Đúng là có những trường hợp mất quá nhiều thời gian, nhưng vấn đề thiếu người, phối hợp và thời gian thường khó giải quyết hơn vấn đề kỹ thuật
Bài này cũng nên đọc cùng câu trả lời trên Reddit của Josh Triplett. Một trong những ví dụ cốt lõi của bài, Mutex, đơn giản là sai
https://old.reddit.com/r/rust/comments/1fpomvp/rewriting_rus...
Sửa: cùng bình luận đó cũng có ở đây
https://news.ycombinator.com/item?id=41655268
Khi học Rust, điều đầu tiên tôi cảm nhận là dường như gần như mọi tính năng có thể tưởng tượng được đều đã có trong đó
Điều đó không có nghĩa là nhóm Rust chưa từng từ chối thứ gì, nhưng mọi người vẫn muốn có thêm nhiều tính năng hơn. Một số là chính đáng, nhưng một số lại trông như kiểu phải đưa vào ngôn ngữ một tính năng chỉ 2% lập trình viên dùng, trong một ngôn ngữ chỉ 1% lập trình viên hiểu được. Một ngôn ngữ phức tạp không cần phải phức tạp hơn nữa. Zig đơn giản hơn và có lẽ nhanh hơn, cộng đồng cũng ít drama hơn nhiều. Mong Zig nhận được nhiều tài trợ hơn
Rust không cố nhét vào mọi tính năng có thể. Chỉ là nếu không hiểu rõ GAT hay TAIT giải quyết vấn đề gì thì có thể cảm thấy như vậy. Zig có thể là một ngôn ngữ hiện đại tốt, nhưng nếu mục tiêu là an toàn bộ nhớ thì nó không phải là lựa chọn
Ví dụ, tương tác giữa
Pinvà future thêm vào ngôn ngữ một mức độ phức tạp phi lý, và tôi nghĩ một phần trong đó là không cần thiết. Tôi ước có một ngôn ngữ giống Rust nhưng hoàn toàn không cóPin. Borrow checker có lẽ cũng có cách đơn giản hóa ở cả cú pháp lẫn triển khai, nhưng tôi vẫn chưa nghĩ cụ thể. Hiện tại trừ khi fork ngôn ngữ thì khó thay đổi, nhưng Rust sẽ không phải là ngôn ngữ cuối cùng dùng borrow checker. Tôi kỳ vọng thế hệ tiếp theo còn nhiều dư địa cải thiện mà không cần tạo ra một ngôn ngữ lớn hơnTôi thấy có drama liên quan đến Rust, nhưng thường nó đến từ phía chống lại việc dùng hoặc chấp nhận Rust. Như vụ ồn ào Rust for Linux gần đây. Dường như đó không phải chuyện thường gặp bên trong cộng đồng, nhưng có thể tôi đã bỏ sót. Zig rất tuyệt, nhưng vẫn chưa sẵn sàng cho production
Tác giả của bình luận được liên kết đã phân tích rộng rãi các primitive đồng bộ hóa của nhiều ngôn ngữ, rồi viết lại các primitive đồng bộ hóa như
MutexvàRwLockcủa Rust để trên từng hệ điều hành lớn chúng dùng trực tiếp các primitive cấp OS bên dướiHọ dùng những thứ như
futexcủa Linux để làm cho chúng nhanh hơn, nhỏ hơn và nhìn chung tốt hơn; trong quá trình đó về cơ bản cũng đã viết một cuốn sách về lập trình song song trong Rust. Nó cũng hữu ích cho lập trình song song không phải Rusthttps://www.oreilly.com/library/view/rust-atomics-and/978109...
Cũng không phải là suốt 7 năm chỉ chơi bời quanh coroutine. Rust đã thêm các hàm bất đồng bộ, trait có thể chứa hàm bất đồng bộ, nhiều tính năng cần thiết để chuẩn hóa
AsyncWritevàAsyncRead, và trên nightly cũng đã có triển khai generator. Hiện vẫn đang thảo luận liệu có chấp nhận độ phức tạp của coroutine hoàn toàn tổng quát hay dừng ở generator. Một số tính năng nhưAsyncIteratorthì chậm, nhưng cũng có rất nhiều công việc đang được thực hiện tích cực. Lúc nào cũng thú vị khi một bên nói ngôn ngữ quá chậm, còn bên kia lại phàn nàn là quá nhanhTrait hàm và hệ thống effect gần đây cũng có những đợt thăm dò thiết kế lớn, và họ muốn đưa ra giải pháp để không phải viết hàm nhiều lần cho từng tổ hợp
async,try,const. Sandbox crate độc hại không phải là vấn đề ở cấp ngôn ngữ; nó cần sự kết hợp giữa verifier và sandbox runtime, và WebAssembly Component có vẻ hứa hẹn hơn. Tuy vậy, họ rất quan tâm đến các capability tại thời điểm biên dịch như lựa chọn allocator hay runtime bất đồng bộ, giả định nền tảng 64-bit; còn sandbox proc macro thì họ muốn không phải để ngăn hành vi ác ý mà để caching chính xácStruct tự tham chiếu không phải là vấn đề cú pháp mà là vấn đề cực kỳ khó để borrow checker xử lý. Partial borrow đã được hỗ trợ trong capture của closure, nhưng mấu chốt là cách duy trì semantic versioning ổn định khi phơi nó ra API công khai. Những phương án như “borrow group” có tên có vẻ nhiều triển vọng. Phía
comptimecũng đang được triển khai theo nhiều hướng, và gần đây cũng đã viết RFC để tăng cườngmacro_rules.implcủaRangeđã đang được thực hiện, gắn với thay đổi không tương thích thông qua edition. Việc kết hợpif letvới AND logic có tính năng unstable và đã gần được ổn định hóa. Cũng đã có nhiều đề xuất cải thiện cú pháp truy cập field qua pointer, nhưng việc mở rộng thêm bề mặt ngôn ngữ là lợi hay hại vẫn là câu hỏi mở. Nhờ các edition của Rust, nếu thiết kế đủ thuyết phục thì có khá nhiều thứ có thể thay đổi. 700 tính năng unstable là vấn đề thực sự, nên cần một công việc lớn để dọn những thứ ít có khả năng được ổn định hóaMacro mang tính khai báo hơn, việc ủy quyền logic của crate
-syscho thư viện dùng chung,cfg(version)/cfg(accessible)sẽ giảm đáng kể nhu cầu người dùng phải tự triển khai, nhưng runtime thì vẫn còn đó. Càng nghĩ thì ACL của cackle càng có vẻ là một cách mở rộng tốt để theo dõi tác vụ trên toàn bộ proc macro, build script và mã runtime, cũng như audit việc sử dụng cây phụ thuộc. Tôi nghe nóicargo-redpencũng đang phát triển thành công cụ audit lời gọi, nhưng tôi đang hình dung một mức cao hơn như cacklehttps://github.com/cackle-rs/cackle
Tôi hiểu việc mọi người phàn nàn rằng Rust đã là một ngôn ngữ lớn nên không muốn nó lớn thêm, nhưng việc giữ nguyên triển khai async nửa chín nửa sống hiện tại không làm ngôn ngữ nhỏ hơn hay đơn giản hơn. Nó chỉ làm ngôn ngữ tệ đi mà thôi. Partial borrow cũng sẽ rất tốt nếu hoạt động được ít nhất trong cùng một crate, chứ không nhất thiết phải là API công khai. Đây là vấn đề liên tục gặp phải khi lập trình thực tế. Tôi cũng thắc mắc vì sao sandbox crate độc hại lại không thể làm ở cấp ngôn ngữ. Nếu một hàm không có mã bên thứ ba
unsafetrong cây lời gọi và cũng không thực hiện system call, thì nó chỉ có thể xử lý các đối số đã được truyền vào, biến cục bộ và global nằm trong scope. Nếu có thể gia cố bức tường này để dùng làm ranh giới bảo mật, có vẻ có thể giảm mạnh rủi ro chuỗi cung ứng phụ thuộcSứ mệnh của Rust ngay từ đầu đã là việc khó: kết hợp hiệu năng, an toàn và khả năng biểu đạt; khi Mozilla rút đi thì Rust đã mất chế độ nhà sáng lập, và phần lớn đội ngũ cốt lõi ban đầu cũng đã rời đi, nên việc tiến triển chậm lại không có gì đáng ngạc nhiên
Cá nhân tôi thấy như vậy vẫn tốt hơn là đi sai đường
Nếu viết lại Rust, có lẽ tôi sẽ đi theo hướng bớt tính năng chứ không phải thêm tính năng
Kiểu như QBE đối với LLVM: cung cấp 70% Rust bằng 10% lượng mã. Có thể làm được nếu bỏ macro và một số tính năng ít dùng
https://c9x.me/compile/
Dù là Rust hay thứ gì khác, trước khi thực sự thử thì rất khó biết khả thi đến mức nào