5 ms·
Doesn't Clojure support this kind of variadic pass through? Admittedly it's a bit more complicated than Ruby's syntax, which I find to be a bit ironic. I'm no
by aeonik 3y ago
Doesn't Clojure support this kind of variadic pass through?
Admittedly it's a bit more complicated than Ruby's syntax, which I find to be a bit ironic.
I'm not sure if Clojure has something equivalent to &block... I think you would just pass a function in Clojure since they are first class?
https://john2x.com/blog/clojure-destructuring.html https://john2x.com/blog/clojure-destructuring.html
- orthoxerox 3y agoI think Clojure prefers macros for things Ruby uses blocks for. For example, `with-open` is a macro that accepts the "block" as a `& body`, while a similar mechanism in Ruby would just take a block/closure that looks like any other statement block.
- eduction 3y agoNot so, much more typical to just take an anonymous function for things ruby uses blocks for. For example, map, or filter (select in ruby), or reduce. “with-open” is a macro because it needs to do something more complicated (create a bunch of bindings then close each one created, in addition to executing a fn body where those bindings are available). Passing an fn is preferred because functions are more broadly preferred in Clojure code to macros, for both practical (more composable) and cultural reasons.
- orthoxerox 3y agoAnonymous functions return from themselves, whereas a block is a special kind of closure that returns from the caller. It's probably less important in Clojure since it is more functional and doesn't use explicit control flow much.
- aeonik 3y agoThis is the part that fascinates me about Code Blocks so much. Is it like an extra break or return statement at the end of it that bails out of the context of whatever method it's running in? Or does it actually return back to the original all site after nested passes of the Code Block?
- orthoxerox 3y agoI am not a rubyist, but a block (which I think is properly called a proc) is different from a regular lambda in that its control flow statements are lexically scoped to the method it is defined in. A return statement in a lambda returns from a lambda (and always succeeds), a return statement in a block returns from the method the block was defined in (and fails with a LocalJumpError if the call frame is no longer on the call stack). I think Kotlin has a similar distinction between lambda expressions that return from the definer (and it ensures that you're passing them to an inline function that won't save the closures for later) and anonymous functions that return from themselves.
- fiddlerwoaroof 3y agoTypically, you can get the syntactic effect of Ruby blocks in a lisp using macros. Clojure tends to be a bit more anti-macro than other lisps, though and so this is less common than it would be in CL or Racket.
- aeonik 3y agoThat makes sense, but isn't the Ruby &block evaluated dynamically? Lisp macros are expanded at compile time. From my limited understanding this would seem like a dynamic, run time, Lisp macro. But I don't know if the &block actually operates on the syntax. It looks it doesnt. From my research, it appears that blocks are more like a lambda that has an extra return statement bolted onto it. It also looks like you can pass them into methods to significantly alter what the method does, and how it returns. Pretty fascinating pattern. I'm not sure how I would implement something similar in Clojure. Maybe higher order functions, with lazy sequences combined with predicate checks.
- epcoa 3y agoRuby blocks are just closures. They’re not macros as they don’t operate on syntax trees. Perhaps the person you are replying to was stating you can emulate some aspect of block syntax with a macro. If not, not sure what they’re saying.
- fiddlerwoaroof 3y agoThe reason people like blocks is that they give you a nice way to embed DSLs in Ruby code. The fact that they’re “just closures” seems like a secondary thing in most uses I’ve seen of them.
- fiddlerwoaroof 3y agoThere’s a pattern called the call-with pattern that gives you this dynamic behavior of blocks. But, in many cases, Ruby and JS use this sort of dynamic “macro” where there’s not really a benefit to dynamic evaluation: with a macro you can always wrap the block of code with an anonymous function at macro-expansion time and opt-in to dynamic evaluation; Ruby blocks (and arrow-function DSLs in JS) force you to pay the overhead of dynamic evaluation even when you only need compile-time information