4 ms·
> He’s described Ruby’s design as starting from a simple Lisp, stripping out macros and s-expressions Put the macros back! It would be so cool!
by danlitt 4mo ago
> He’s described Ruby’s design as starting from a simple Lisp, stripping out macros and s-expressions
Put the macros back! It would be so cool!
- KerrAvon 4mo agoYou kind of don't need them in Ruby, because everything is a method or an object or a closure and you can dynamically create and alter those at runtime. That's why Ruby is really good for ad-hoc DSLs in ways that Rust and Swift really are not.
- yxhuvud 4mo agoCrystal don't have the dynamicity but has macros to get the next best thing. Most meta magic in Ruby in good code are done at startup anyhow so you don't miss out on that much. YMMV.
- bashkiddie 4mo ago> because everything is a method or an object or a closure well, except for pattern matching. That is just syntax.
- shawn_w 4mo agoPut the s-expressions back too.
- matheusmoreira 4mo agoMacros depend on homoiconicity which Ruby sacrificed in order to have familiar syntax.
- ameliaquining 4mo agoHomoiconicity makes macros slightly more syntactically elegant, but is not at all necessary. Rust has macros and isn't homoiconic at all.
- matheusmoreira 4mo agoC has macros too, but it's a second preprocessor language. They both accomplish metaprogramming, but it's questionable whether they're both the same lisplike "macros" we're talking about. Ruby source could be passed through the C preprocessor and get C macros that way. I've actually seen Java code that does just that.
- ameliaquining 4mo agoC macros are definitely much weaker; they're not by themselves Turing-complete (except maybe with vendor-specific extensions? I'm not an expert here). Rust has both macros by example (precisely analogous to Scheme macros, and equal in power) and procedural macros (conceptually analogous to Common Lisp macros, allowing arbitrary code at macro evaluation time, but I don't know enough about Common Lisp to say whether there are differences in power).
- matheusmoreira 4mo agoHow does it work internally? It would have to output the new source code as data somehow, and have the Rust compiler consume it. How does that happen? The lispy "macros" I speak of are FEXPRs, just everyday normal functions that just happen to not evaluate their arguments, they receive the source code as lists instead. It's easy to manipulate those lists and evaluate the result. Lisps themselves moved away from FEXPRs because they were "too powerful" and made the compiler's life hard. Common Lisp and Scheme macros are the more restricted versions that allow compilers to make more assumptions, thereby enabling more aggressive optimization.
- ameliaquining 4mo agoYes, a Rust procedural macro is a function that takes a Rust syntax tree as an argument and returns a Rust syntax tree. When you use it, the compiler compiles it (for the host architecture), dynamically loads it into the compiler process, calls it, and inserts the output into the code to be compiled. https://doc.rust-lang.org/book/ch20-05-macros.html#procedural-macros-for-generating-code-from-attributes https://doc.rust-lang.org/book/ch20-05-macros.html#procedura... I don't see why this would inhibit optimization, unless you mean it slows down compilation, in which case, yep, that's a real and rather notorious downside.