1 điểm bởi GN⁺ 9 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Biến mã Ruby thành binary native độc lập có thể thực thi, và nhắm tới tốc độ chạy nhanh hơn trung bình nhân khoảng 11,6 lần so với CRuby miniruby mới nhất nhờ suy luận kiểu ở mức toàn bộ chương trình và sinh mã C
  • Pipeline biên dịch dùng parser dựa trên Prism để chuyển Ruby thành văn bản AST, sau đó backend self-hosting thực hiện suy luận kiểu và sinh mã C, rồi dùng trình biên dịch C tiêu chuẩn để tạo binary standalone
  • Backend trình biên dịch có cấu trúc self-hosting được viết bằng Ruby, và sau quá trình bootstrap thì gen2.c == gen3.c được thiết lập, khép kín vòng lặp tự biên dịch lại chính nó
  • Bổ sung các tối ưu hóa ở thời điểm biên dịch như làm phẳng nối chuỗi, value-type promotion, loop-invariant length hoisting, static symbol interning, tự động nâng cấp bigint, đồng thời giảm phụ thuộc runtime bên ngoài bằng regexp engine tích hợp, bigint và runtime dạng header đơn
  • Không hỗ trợ eval, metaprogramming, Thread hay xử lý encoding tổng quát, nhưng cho thấy tính thực tiễn của biên dịch Ruby AOT nhờ hình thức phân phối chạy không cần Ruby và chênh lệch hiệu năng lớn trong các workload thiên về tính toán

Cách hoạt động

  • Pipeline biên dịch gồm luồng parse file Ruby rồi tuần tự hóa thành tệp văn bản AST, sau đó qua suy luận kiểu và sinh mã C để tạo binary native bằng trình biên dịch C tiêu chuẩn
  • spinel_parse dùng Prism và libprism để parse Ruby; khi không có binary C thì dùng đường thay thế với CRuby và gem Prism
  • spinel_codegen chạy như một binary native self-hosted, nhận AST rồi thực hiện suy luận kiểu + sinh mã C
  • Bước cuối cùng biên dịch mã nguồn C cùng header runtime bằng cc -O2 -Ilib -lm, và binary kết quả được tạo ở dạng standalone

Self-Hosting

  • Chuỗi bootstrap được khép kín theo cách tạo AST bằng CRuby + spinel_parse.rb, tạo gen1.cbin1 bằng CRuby + spinel_codegen.rb, rồi dùng lại binary đã sinh ra để tạo gen2.c, gen3.c
  • gen2.c == gen3.c xác nhận rằng bootstrap loop đã được khép kín
  • Backend spinel_codegen.rb được viết bằng tập con Ruby mà chính Spinel có thể tự biên dịch
    • classes, def, attr_accessor
    • if/case/while
    • each/map/select, yield
    • begin/rescue
    • thao tác String, Array, Hash và File I/O
  • Backend không dùng metaprogramming, eval, require

Hiệu năng và benchmark

  • Trạng thái hiện tại là 74 bài test vượt qua, 55 benchmark vượt qua
  • Theo 28 benchmark, trung bình nhân nhanh hơn khoảng 11,6 lần so với CRuby miniruby mới nhất
  • Mốc so sánh là bản dựng CRuby miniruby mới nhất không kèm bundled gem; ngay cả khi so với hệ thống ruby 3.2.3 vốn nhanh hơn, nó vẫn vượt trội trong workload nặng về tính toán
  • Hiệu năng tính toán

    • life: 20ms so với 1.733ms, nhanh hơn 86,7 lần
    • ackermann: 5ms so với 374ms, nhanh hơn 74,8 lần
    • mandelbrot: 25ms so với 1.453ms, nhanh hơn 58,1 lần
    • phiên bản đệ quy fib: 17ms so với 581ms, nhanh hơn 34,2 lần
    • nqueens: 10ms so với 304ms, nhanh hơn 30,4 lần
    • tarai: 16ms so với 461ms, nhanh hơn 28,8 lần
    • tak: 22ms so với 532ms, nhanh hơn 24,2 lần
    • matmul: 13ms so với 313ms, nhanh hơn 24,1 lần
    • sudoku: 6ms so với 102ms, nhanh hơn 17,0 lần
    • partial_sums: 93ms so với 1.498ms, nhanh hơn 16,1 lần
    • fannkuch: 2ms so với 19ms, nhanh hơn 9,5 lần
    • sieve: 39ms so với 332ms, nhanh hơn 8,5 lần
    • fasta: 3ms so với 21ms, nhanh hơn 7,0 lần
  • Cấu trúc dữ liệu và GC

    • rbtree: 24ms so với 543ms, nhanh hơn 22,6 lần
    • splay tree: 14ms so với 195ms, nhanh hơn 13,9 lần
    • huffman: 6ms so với 59ms, nhanh hơn 9,8 lần
    • so_lists: 76ms so với 410ms, nhanh hơn 5,4 lần
    • binary_trees: 11ms so với 40ms, nhanh hơn 3,6 lần
    • linked_list: 136ms so với 388ms, nhanh hơn 2,9 lần
    • gcbench: 1.845ms so với 3.641ms, nhanh hơn 2,0 lần
  • Chương trình thực tế

    • json_parse: 39ms so với 394ms, nhanh hơn 10,1 lần
    • bigint_fib tính số 1000 chữ số: 2ms so với 16ms, nhanh hơn 8,0 lần
    • ao_render: 417ms so với 3.334ms, nhanh hơn 8,0 lần
    • pidigits: 2ms so với 13ms, nhanh hơn 6,5 lần
    • str_concat: 2ms so với 13ms, nhanh hơn 6,5 lần
    • template engine: 152ms so với 936ms, nhanh hơn 6,2 lần
    • csv_process: 234ms so với 860ms, nhanh hơn 3,7 lần
    • io_wordcount: 33ms so với 97ms, nhanh hơn 2,9 lần

Các tính năng Ruby được hỗ trợ

  • Ở lớp Core, hỗ trợ classes, inheritance, super, mixin include, attr_accessor, Struct.new, alias, module constants và open classes cho các kiểu dựng sẵn
  • Control Flow, hỗ trợ if/elsif/else, unless, case/when, pattern matching case/in, while, until, loop, for..in, break, next, return, catch/throw, &.
  • Blocks, hỗ trợ yield, block_given?, &block, proc {}, Proc.new, -> x { }, method(:name), cùng các block method như each, map, select, reduce, sort_by, times, upto, downto
  • Exceptions, hỗ trợ begin/rescue/ensure/retry, raise, và lớp ngoại lệ do người dùng định nghĩa
  • Types bao gồm Integer, Float, String, Array, Hash, Range, Time, StringIO, File, Regexp, Bigint, Fiber
    • Giá trị đa hình được xử lý bằng tagged unions
    • Có nullable object types T? cho cấu trúc dữ liệu tự tham chiếu
  • Global Variables như $name được biên dịch thành biến C tĩnh, và sai lệch kiểu được phát hiện ngay khi biên dịch
  • I/O hỗ trợ puts, print, printf, p, gets, ARGV, ENV[], File.read/write/open, system(), backtick

Chuỗi, biểu thức chính quy, symbol, Bigint, Fiber

  • Strings hỗ trợ cả chuỗi bất biến lẫn có thể thay đổi; << tự động nâng cấp thành chuỗi mutable sp_String để append tại chỗ với độ phức tạp O(n)
  • +, interpolation, tr, ljust/rjust/center và các method chuẩn hoạt động trên cả hai biểu diễn chuỗi
  • Các so sánh như s[i] == "c" được tối ưu để truy cập trực tiếp mảng char và xử lý không cần cấp phát
  • Các phép nối như a + b + c + d được làm phẳng thành một lần gọi sp_str_concat4 hoặc sp_str_concat_arr, giảm N-1 lần cấp phát
  • str.split(sep) trong vòng lặp tái sử dụng cùng một sp_StrArray, giúp loại bỏ 4 triệu lần cấp phát trong csv_process
  • Regexp dùng NFA regexp engine tích hợp, không phụ thuộc bên ngoài
    • Hỗ trợ =~, $1-$9, match?, gsub, sub, scan, split
  • Bigint dùng số nguyên độ chính xác tùy ý dựa trên mruby-bigint
    • Tự động nâng cấp trong các mẫu như vòng lặp nhân q = q * k
    • Được link như thư viện tĩnh và chỉ được đưa vào khi thực sự dùng
  • Fiber cung cấp đồng thời hợp tác dựa trên ucontext_t
    • Hỗ trợ Fiber.new, Fiber#resume, Fiber.yield và truyền giá trị
    • Biến tự do được capture bằng các cell được nâng lên heap
  • Symbols được cài đặt bằng kiểu sp_sym tách biệt với chuỗi
    • Giữ nguyên :a != "a"
    • Symbol literal được intern ở thời điểm biên dịch thành hằng SPS_name
    • String#to_sym chỉ dùng pool động khi cần
    • Hash với khóa symbol dùng sp_SymIntHash để lưu trực tiếp khóa số nguyên thay vì chuỗi, nên loại bỏ strcmp và cấp phát chuỗi động

Quản lý bộ nhớ và kiểu giá trị

  • Quản lý bộ nhớ dùng GC mark-and-sweep, gồm size-segregated free lists, non-recursive marking, sticky mark bits
  • Các class nhỏ và đơn giản được tự động nâng cấp thành value types và đặt trên stack
    • điều kiện là tối đa 8 trường vô hướng
    • không có kế thừa
    • không bị thay đổi thông qua tham số
  • Cấp phát 1 triệu lần cho class 5 trường giảm từ 85ms xuống còn 2ms
  • Chương trình chỉ dùng value types sẽ không xuất kèm runtime GC

Tối ưu hóa

  • Thực hiện nhiều tối ưu hóa ở thời điểm biên dịch dựa trên suy luận kiểu toàn bộ chương trình
  • Value-type promotion biến các class nhỏ bất biến thành đối tượng stack dạng C struct, loại bỏ overhead GC
  • Constant propagation inline trực tiếp các hằng literal đơn giản như N = 100 vào nơi sử dụng thay vì truy vấn cst_N
  • Loop-invariant length hoisting chỉ tính độ dài một lần trước vòng lặp cho các biểu thức như while i < arr.length
    • Nếu phần thân thay đổi đối tượng nhận, như arr.push, tối ưu này sẽ bị tắt
  • Method inlining gắn static inline cho các method ngắn, không đệ quy, tối đa 3 câu lệnh để khuyến khích gcc inline
  • String concat chain flattening rút chuỗi nối thành một lời gọi duy nhất, loại bỏ việc tạo chuỗi trung gian
  • Bigint auto-promotion tự động nâng các mẫu cộng tự tham chiếu hoặc nhân lặp sang bigint
  • Bigint to_s dùng mpz_get_str của mruby-bigint để xử lý theo kiểu divide-and-conquer O(n log²n)
  • Static symbol interning biến "literal".to_sym thành hằng thời điểm biên dịch SPS_<name>; chỉ thêm pool runtime khi dùng interning động
  • Trong sub_range, chuỗi có độ dài đã được hoist dùng sp_str_sub_range_len để bỏ qua lời gọi strlen nội bộ
  • line.split(",") trong vòng lặp tái sử dụng sp_StrArray hiện có
  • Dead-code elimination dùng -ffunction-sections -fdata-sections--gc-sections để loại bỏ hàm runtime không dùng khỏi binary cuối
  • Iterative inference early exit dừng ngay vòng lặp tìm điểm cố định khi 3 mảng chữ ký của param, return, ivar không còn thay đổi
    • Phần lớn chương trình hội tụ sau 1–2 vòng thay vì 4 vòng đầy đủ
    • Thời gian bootstrap giảm khoảng 14%
  • parse_id_list byte walk thay parser danh sách trường AST được gọi khoảng 120 nghìn lần trong quá trình tự biên dịch từ s.split(",") sang duyệt thủ công s.bytes[i], giảm số lần cấp phát mỗi lần gọi từ N+1 xuống còn 2
  • Mã C được sinh ra giữ warning-free build ở mức cảnh báo mặc định, và harness dùng -Werror để lộ hồi quy ngay lập tức

Kiến trúc

  • Cấu trúc kho mã được chia thành các thành phần sau
    • spinel: script wrapper một lệnh dựa trên POSIX shell
    • spinel_parse.c: frontend C 1.061 dòng từ libprism sang AST văn bản
    • spinel_codegen.rb: backend compiler 21.109 dòng từ AST sang mã C
    • lib/sp_runtime.h: header thư viện runtime 581 dòng
    • lib/sp_bigint.c: số nguyên độ chính xác tùy ý 5.394 dòng
    • lib/regexp/: regexp engine tích hợp 1.759 dòng
    • test/: 74 bài test chức năng
    • benchmark/: 55 benchmark
    • Makefile: tự động hóa build
  • Runtime lib/sp_runtime.h chứa GC, cài đặt array/hash/string và các hỗ trợ runtime khác trong một tệp header duy nhất
  • Mã C sinh ra include header này, còn linker chỉ lấy phần cần thiết từ libspinel_rt.a
    • bigint
    • regexp engine
  • Parser có hai cách triển khai
    • spinel_parse.c link trực tiếp libprism để chạy không cần CRuby
    • spinel_parse.rbfallback CRuby dùng gem Prism
  • Cả hai parser tạo ra cùng một đầu ra AST, và wrapper spinel sẽ ưu tiên binary C nếu có thể
  • require_relative được giải quyết ở thời điểm parse để inline các tệp được tham chiếu

Hạn chế

  • No eval: không hỗ trợ eval, instance_eval, class_eval
  • No metaprogramming: không hỗ trợ send, method_missing, define_method động
  • No threads: không hỗ trợ Thread, Mutex, chỉ hỗ trợ Fiber
  • No encoding: giả định UTF-8 và ASCII
  • No general lambda calculus: không xử lý -> x { } lồng sâu và lời gọi []

Phụ thuộc và mô hình thực thi

  • Phụ thuộc lúc build là thư viện C libprism và CRuby cho bootstrap ban đầu
  • Không có phụ thuộc runtime; binary sinh ra chỉ cần libc + libm
  • Regexp dùng engine tích hợp nên không cần thư viện ngoài
  • Bigint được tích hợp sẵn nhưng chỉ link khi thực sự dùng
  • Prism là parser Ruby mà spinel_parse sử dụng
    • make deps tải tarball gem prism từ rubygems.org và giải nén mã C vào vendor/prism
    • Nếu prism gem đã được cài, hệ thống sẽ tự phát hiện
    • Cũng có thể chỉ định đường dẫn tùy chỉnh bằng PRISM_DIR=/path/to/prism
  • CRuby chỉ cần cho bootstrap ban đầu; sau make, toàn bộ pipeline chạy không cần Ruby

Lịch sử dự án

  • Spinel ban đầu được triển khai bằng C, quy mô 18K lines, và vẫn còn trong nhánh c-version
  • Sau đó dự án đi qua nhánh ruby-v1, được viết lại bằng Ruby
  • master hiện tại là phiên bản được viết lại bằng tập con Ruby có thể self-hosting

Giấy phép

  • Sử dụng MIT License
  • Tuân theo tệp LICENSE

1 bình luận

 
Ý kiến trên Hacker News
  • Nếu là thứ do Matz làm thì hẳn ông ấy cũng hiểu rất rõ những giới hạn của Ruby semantics, nên tạo được cảm giác tin cậy
    Luận văn thạc sĩ của tôi cũng là về AOT JS compiler, chạy được thật nhưng bị ràng buộc dữ liệu đầu vào quá lớn nên cuối cùng phải bỏ dở
    Hồi đó các lập trình viên JS chưa quen với việc tự giác tuân thủ những ràng buộc như vậy, và các đầu vào vốn dĩ không thể biết trước như JSON.parse là trở ngại lớn
    Bây giờ nhờ TypeScript nên có thể thực tế hơn rất nhiều so với khi đó
    Chỉ nhìn vào lambda calculus nói chung cũng thấy giới hạn của suy luận kiểu là rất rõ ràng, và các bài báo phía Matt Might hay dự án Shed-skin Python cũng bộc lộ những ràng buộc tương tự
    Tôi tò mò eval, send, method_missing, define_method thực sự phổ biến đến mức nào trong mã Ruby ngoài đời, và cũng tò mò các đầu vào parse không kiểu, ví dụ JSON input, thường được xử lý ra sao

    • Thiết kế này trông khá pragmatic
      Việc parse Ruby khó đến mức còn khó hơn cả khâu biên dịch, nên họ dùng Prism, rồi sinh ra mã C
      Bản thân việc hiện thực các Ruby semantics cơ bản thì không hẳn khó đến vậy
      Ngược lại, tôi đang vật lộn với một self-hosting AOT compiler cũ viết bằng Ruby thuần, vì cố chấp tự làm parser riêng nên đã tự chọn con đường khó hơn nhiều
      Tôi học được khá sớm rằng 80% đầu có thể làm tương đối sơ sài mà vẫn chạy được phần lớn mã Ruby, còn “80% thứ hai” mới thực sự khó thì lại tập trung ở những thứ Matz đã bỏ ra khỏi dự án này và khỏi mruby, như encoding hay đủ loại tính năng phụ trợ
      Nói thật là trong Ruby có không ít tính năng mà tôi chưa từng thấy một lần nào trong mã thực tế, nên nếu vài cái bị deprecated tôi cũng không thấy lạ
      send, method_missing, define_method thì rất phổ biến
      Các ràng buộc thì tương tự mruby, nhưng ngay cả dưới các ràng buộc đó vẫn có chỗ để dùng
      Hỗ trợ send, method_missing, define_method tương đối dễ
      Còn hỗ trợ eval() thì cực kỳ đau đầu
      Tuy vậy, một tỷ lệ lớn eval() trong Ruby có thể được quy về phiên bản block của instance_eval theo cách tĩnh, nên trong những trường hợp đó AOT compile khá dễ
      Ví dụ nếu chuỗi truyền vào eval() có thể biết trước hoặc phân rã được một cách tĩnh thì khả năng giải quyết sẽ lớn
      Trên thực tế, nhiều cách dùng eval() là không cần thiết hoặc chỉ gần như cách né introspection đơn giản, nên có thể xử lý bằng kiểm tra tĩnh
      Compiler của tôi cũng định nếu chỗ đó trở thành nút thắt thì sẽ đụng vào từ đó trước
    • Cần khá nhiều tính năng kiểu này mới tạo ra được Rails-style magic
      Việc ingest JSON không kiểu cũng có lẽ sẽ dùng những cơ chế như vậy
      Nếu bỏ chúng đi thì sẽ còn lại một ngôn ngữ nhỏ, dễ đọc, không có type mạnh như Crystal nhưng cũng không dựa vào metaprogramming nhiều như Ruby chính thức
      Vì thế tiềm năng có vẻ khá lớn, nhưng rốt cuộc vẫn phải chờ thời gian mới biết được
    • Nếu là cách compile Ruby sang Objective-C thì có vẻ sẽ vừa hỗ trợ được toàn bộ tính năng Ruby vừa nhanh hơn Ruby interpreter
    • Tôi thuộc phe dùng eval khá thường xuyên
      Có thể không dùng cũng được, nhưng với tôi như vậy ergonomic hơn
    • Theo kinh nghiệm của tôi, cái thú vị là eval, exec, define_method, và pattern tạo class mới bằng Class.new, Struct.new
      Phần lớn việc dùng chúng tập trung vào thời điểm boot của app hoặc trong lúc require file, nên ở một khía cạnh nào đó nó đã khá giống giai đoạn compile rồi
  • Đây là thứ Matz vừa trình bày tại RubyKaigi 2026
    Dù còn mang tính thử nghiệm, ông ấy đã làm ra nó trong khoảng một tháng với sự trợ giúp của Claude, và demo trực tiếp cũng thành công
    Tên gọi được lấy từ con mèo mới của Matz, còn tên con mèo thì bắt nguồn từ tên mèo trong Card Captor Sakura, nơi nó lại ghép cặp với một nhân vật tên là Ruby

    • Nhiều người hay nói AI sẽ tự làm cả chương trình từ đầu đến cuối, nhưng tôi nghĩ kịch bản thực tế hơn là biến 10x programmer thành 100x programmer
      Với người như Matz thì có khi là đẩy từ 100x lên 500x
    • Trong đầu tôi, Spinel gần đây nhất là nhân vật bên Steven Universe, nên hoàn toàn không nhận ra trò chơi chữ Spinel/Ruby (Moon), nhưng biết rồi thì thấy cả ngày vui hơn hẳn
    • Tôi thì đương nhiên tưởng là đang nói đến khoáng vật spinel :)
      https://en.wikipedia.org/wiki/Spinel
    • Cảm ơn
      Có vẻ video vẫn chưa phát trực tiếp, và hình như đang được đăng dần từng cái lên kênh này
      https://www.youtube.com/@rubykaigi4884/videos
    • Câu chuyện về nguồn gốc tên con mèo đó nghe khá đáng ngờ nếu xét tới Ruby Central drama và mối quan hệ với các nhà sáng lập Spinel.coop
      Tên dự án cũng tạo cảm giác như được đặt theo cảm xúc
  • Rõ ràng là rất ấn tượng, nhưng trông có vẻ không thể bảo trì nếu không có AI agent
    spinel_codegen.rb dài 21 nghìn dòng, có method lồng tới 15 cấp
    Vốn dĩ mã compiler đã khó mà đẹp, nhưng ngay cả theo tiêu chuẩn đó thì cái này cũng có vẻ rất khó để con người quản lý

    • Mã compiler nếu có thời gian thì hoàn toàn có thể làm cho đẹp
      Compiler có ranh giới subsystem rõ ràng và handoff giữa các giai đoạn cũng mạch lạc, nên thực ra lại thuộc nhóm dễ modular hóa nhất
      Vấn đề thường là sau khi đã làm cho nó chạy được thì không còn thời gian refactor, và thế là sự bừa bộn cứ phình ra
    • spinel_codegen.rb gần như ở mức eldritch horror
      Dùng Claude thì tôi cũng luôn ra kiểu spaghetti code thế này, nên từng tự hỏi không biết mình đang làm sai gì
      Nhưng nhìn thấy cả trong một dự án thực sự thú vị do người mà tôi xem là lập trình viên top đầu tạo ra, chất lượng mã ở nhiều chỗ cũng khá tệ, thì hóa ra không phải chỉ mình tôi
      Ví dụ infer_comparison_type() chưa phải ca tệ nhất và cũng không khó đọc, nhưng vẫn có cách hiện thực đơn giản và rõ ràng hơn nhiều mà Claude lại không đi tới được
      Nếu gom các toán tử so sánh vào Set rồi xử lý bằng include? thì sẽ ngắn hơn, nhanh hơn, dễ đọc hơn và dễ bảo trì hơn
      Thế mà Claude lúc nào cũng trôi về kiểu chuỗi if-return, thậm chí còn có cảm giác nó lạ lẫm cả với if-else
      Codebase do Claude viết của tôi cũng đầy những pattern như vậy, nên giờ tôi biết không chỉ mình mình gặp thế
      Ngược lại, các file khác tốt hơn nhiều, đặc biệt là thư mục lib có vẻ tương ứng với thư mục ext trong repo Ruby chính và chất lượng khá ổn
      API cũng rõ ràng chịu ảnh hưởng từ MRI Ruby, và dù phần hiện thực khác khá nhiều, có vẻ Matz đã hướng nó mô phỏng một phần API gốc nên đầu ra trông gọn gàng hơn
      [1] https://github.com/matz/spinel/blob/98d1179670e4d6486bbd1547...
    • Ở giai đoạn hiện tại, tôi không nghĩ việc con người có thể tự tay bảo trì nó quan trọng đến thế
      Chỉ cần test và benchmark qua là tạm ổn rồi
      Tuy vậy, tôi vẫn nghi ngờ liệu file khổng lồ như vậy có thật sự dễ cho AI xử lý hay không
      Tôi đang cố giới hạn file trong khoảng dưới 300 dòng, và nghĩ rằng mã dễ hiểu với con người thì cũng sẽ dễ cho coding agents
  • Các ràng buộc được nói là như sau
    No eval: eval, instance_eval, class_eval
    No metaprogramming: send, method_missing, define_method (động)
    No threads: Thread, Mutex (có hỗ trợ Fiber)
    No encoding: giả định UTF-8/ASCII
    No general lambda calculus: -> x { } lồng sâu kèm lời gọi []
    Riêng giả định UTF-8/ASCII thì cá nhân tôi không thấy là ràng buộc lớn, nhưng phần còn lại có vẻ sẽ là hạn chế thực sự với khá nhiều chương trình
    Và có vẻ sẽ cần rất nhiều công sức nếu muốn đưa các phần đó trở lại

    • Vậy là khá nhiều phần magic của Ruby biến mất
  • Tôi đã dùng Ruby rất lâu, và với tư cách người từng dùng hết tất cả những tính năng được liệt kê, thứ mà sau cả quá trình tiến hóa tôi lại muốn chính là phiên bản Ruby đơn giản như thế này
    Nó đơn giản hơn, dễ hiểu hơn mà vẫn giữ được chất thẩm mỹ rất Ruby
    Giờ nhờ LLM mà năng suất sinh code đã cao đến mức không còn cần phải dùng metaprogramming để cắt boilerplate vì năng suất lập trình viên như trước nữa
    Bởi vì tỷ lệ lập trình viên trực tiếp tự viết code đang giảm đi

    • Nếu thứ bạn muốn chỉ là Ruby aesthetic thì Crystal cũng có thể rất hợp
      Cú pháp tương tự và có static type system, từ đó dẫn tới mã biên dịch hiệu quả hơn
    • Không có eval thì tôi còn thấy tốt hơn, nhưng đến cả threads và mutexes cũng không có thì hơi tiếc
      Việc thiếu define_method thì xét theo công dụng của nó tôi còn hiểu được
      Nhưng sendmethod_missing lại rất phổ biến trong các thư viện hiện có, và cách hiện thực cũng có vẻ không đến mức quá khó, kiểu dựng bảng tra cứu trong bộ nhớ ngay lúc compile
      Nên tôi không rõ đây là cố ý bỏ đi, hay chỉ là chưa làm tới đó
      Tôi mong là vế sau, nhưng ít nhất ở thời điểm hiện tại thì vì vấn đề tương thích nên có lẽ khó đem vào thực chiến
    • Ưu điểm của metaprogramming vốn không phải là viết ít code hơn
      Mà là giảm lượng code phải đọc
  • Cái này thật sự rất ngầu, và tôi đã chờ một AOT compiler cho Ruby từ lâu
    Chỉ tiếc là không có fallback cho eval hay metaprogramming, nhưng có vẻ họ làm vậy để tập trung vào một subset nhỏ mà hiệu năng cao
    Tôi hy vọng gem tạo bằng AOT compiler này có thể tương tác tốt với MRI
    Việc đóng gói hoặc bundle Ruby chuẩn và gem vẫn cần tebako, kompo, ocran, và trước đây cũng từng có các dự án như ruby-packer, traveling ruby, jruby warbler
    Có thêm một lựa chọn nữa thì tốt, nhưng tôi vẫn mong sẽ có phiên bản quyết định cuối cùng với UX cho lập trình viên tốt hơn

    • Đúng vậy, gần đây tôi cũng phải fork warbler
      Vì nó đã quá lâu không được cập nhật
  • Tôi thắc mắc vì sao lại no threads
    Ruby scheduler và phần hiện thực pthread phía dưới có vẻ như vẫn có thể hoạt động ổn ngay cả trong vùng C, nên tôi tự hỏi có phải họ nhắm tới zero dependency không
    Nếu không phải là dự định thêm optional extension sau này hay chỉ là tạm thời chưa làm, thì lựa chọn này thấy hơi lạ

    • Tôi vẫn chưa thấy bằng chứng nào cho thấy họ đã cố ý quyết định không hỗ trợ cái này
      Có lẽ chỉ là chưa làm tới đó thôi
      Multithreading vốn đã cực khó để làm cho đúng
  • Việc làm ra nó chỉ trong hơn một tháng thật đáng kinh ngạc
    Dù có nói gì về AI đi nữa thì khi rơi vào tay lập trình viên giỏi, nó đúng là tạo ra mức tăng tốc khủng khiếp

    • Cả ngành thì bắt đầu bằng việc dựng đủ thứ như agent harness, SOUL.md, phân quyền, skills, MCPs, hooks, env
      Còn Matz thì có cảm giác chỉ cần gem env|info với find là đủ
  • Vì đây là thứ do Matz làm, tôi tò mò khả năng thực tế để nó trở thành một phần của Ruby core trong tương lai là bao nhiêu
    Và nếu vậy thì nó sẽ đe dọa Crystal đến mức nào

    • Crystal có static type system rõ ràng và được tối ưu cho AOT compile ngay từ cấp độ ngôn ngữ
      Những đặc tính như vậy gần như thiết yếu để compile và bảo trì các chương trình lớn
      Còn cái này chỉ là subset Ruby bị giới hạn, nên đa số gem Ruby phổ biến có lẽ sẽ không chạy nguyên trạng
      Xét ở góc độ là một subset ngôn ngữ nhắm tới biên dịch C, nó có vẻ gần với PreScheme hơn
      Ở giai đoạn hiện tại tôi không nghĩ hai bên đang cạnh tranh trực tiếp trong cùng một không gian
      Ruby đầy đủ gần như chắc chắn vẫn sẽ cần JIT
      [1]: https://prescheme.org/
    • Theo một góc nhìn khác, rốt cuộc LLM có lẽ sẽ tiến tới điểm có thể tuôn ra formal specification cho bất kỳ ngôn ngữ nào ta muốn
      Kiểu như màn báo thù của Rational Unified Process và các công cụ như Enterprise Architect
      Khác biệt chỉ là thay vì UML diagram thì giờ thứ được đưa ra là file markdown
  • Cái này có vẻ sẽ hữu ích trong mảng infrastructure tools
    Ví dụ có thể hình dung ra một bundler viết bằng Ruby nhưng được compile tĩnh, nên đồng thời kiêm luôn vai trò công cụ cài Ruby kiểu RVM
    Buildpack Ruby hiện tại cũng viết bằng Ruby, nhưng phải bootstrap bằng bash nên rất phiền và sinh ra edge case
    CNB được viết bằng Rust để tránh vấn đề đó, và ý tưởng phát hành một binary duy nhất không phụ thuộc gì thật sự rất mạnh