URI:
        _______               __                   _______
       |   |   |.---.-..----.|  |--..-----..----. |    |  |.-----..--.--.--..-----.
       |       ||  _  ||  __||    < |  -__||   _| |       ||  -__||  |  |  ||__ --|
       |___|___||___._||____||__|__||_____||__|   |__|____||_____||________||_____|
                                                             on Gopher (inofficial)
  HTML Visit Hacker News on the Web
       
       
       COMMENT PAGE FOR:
  HTML   Lisp's Influence on Ruby
       
       
        muvlon wrote 13 hours 1 min ago:
        Most of the points listed are hardly considered lispy anymore these
        days, Python also has most of these.
        
        Where Ruby's lisp lineage really shows is the fact that it's got
        Kernel#callcc, aka call with current continuation. It doesn't get any
        lispier than that!
       
          t0mpr1c3 wrote 2 hours 40 min ago:
          `callcc` was obsoleted about 10 years ago. I don't know if it has
          been removed yet.
          
  HTML    [1]: https://bugs.ruby-lang.org/issues/10548
       
        insumanth wrote 14 hours 47 min ago:
        As I read this, all of my favorite things about ruby compared to
        something like python were influenced by lisp. 
        Ruby is a joy to program and it seems mostly due to design influence
        from lisp.
       
        neilv wrote 19 hours 10 min ago:
        > Both marks come from Scheme, where [...]
        
        Reminds me of an email I wish I still had.
        
        Circa 2000, I wrote that I was leaning towards moving to Scheme, for
        more rapid R&D work than I could do in Java.
        
        Some nice-sounding person I didn't know emailed me from Japan, to
        mention a language I hadn't heard of, called Ruby.
        
        I don't know whether the person was Yukihiro Matsumoto himself, but
        it's a small world.
       
        0x3444ac53 wrote 21 hours 37 min ago:
        I've never been more thoroughly convinced that I would like ruby more
        than from this article. I'm currently stuck reaching for python a lot
        of the time (absolutely love it tbc), but maybe it's worth changing
        things up and trying to give ruby a shot.
        
        It was one of the first programming languages I was introduced to at 16
        or so, but an older person that I looked up to told me it would get me
        stuck in "hobby coder land". He was wrong in so many ways, but even if
        he was right, I wanna have fun in my hobby code :)
       
          Kaliboy wrote 19 hours 41 min ago:
          I've had one job in my life, still at the same company. (8 years).
          
          I applied cause the listing mentioned Python, and I was programming
          in Python at the time.
          
          Once I started they were like yeah we put that there to reach a
          broader public but we use Ruby (on Rails).
          
          So that's what I learned. I've    just returned to Python via LLM's. I
          literally have not felt the need nor desire to use Python once I got
          used to writing Ruby.
       
          NuclearPM wrote 19 hours 46 min ago:
          Tbc?
       
            dmitris wrote 14 hours 56 min ago:
            to be clear [IMO]
       
        somewhereoutth wrote 23 hours 32 min ago:
        was this before or after Lisp's epiphany for lexical binding?
       
        hyperrail wrote 1 day ago:
        One way I find traditional Lisp style more painful for functional code
        than Ruby is that fully functional-style Lisp pushes me to read and
        write code the opposite way from how I think about it. In the author's
        example:
        
            orders
              .select { |o| o.placed_at > 1.week.ago }
              .group_by(&:customer_id)
              .transform_values { |group| group.sum(&:total) }
        
        the equivalent Lisp code would either be written in imperative style as
        multiple statements that each write to a temporary variable or (let)
        binding, or would look like this:
        
            (reduce #'+
              (map (lambda (o) (getf o 'total))
            ; this group_by replacement function
            ; might be written as hash-table code
            (my-group-by 'customer-id
              (remove-if-not
                (lambda (o)
                  (>
                (getf o 'placed-at)
                (- (my-now) (* 60 60 24 7))))
                orders))))
        
        where I now have to read from bottom to top to understand the order of
        operations on the `orders` record set, even though when I wrote the
        code earlier, I "logically" thought from first operation to last when
        deciding which high-level operations to use in which order.
        
        Other imperative languages that support functional code either make you
        do things imperatively to get the "logical" ordering of functional
        operations like I feel Lisp pushes you to do, or they do something like
        Ruby where things can be chained left to right in a "single" statement
        even for operations that were not thought of ahead of time by the
        creators of opaque data structures you later need to operate on.
        (Everything is a user-extensible object like Ruby, unified function
        call syntax in D, extension methods in C#, or pipelines of structured
        objects in PowerShell.)
       
          tmtvl wrote 22 hours 5 min ago:
          It could just be written like:
          
            (~> orders
              (filter (lambda (order)
                    (timestamp> (order-date order)
                        (timestamp- (now) 7 :days))))
              (group-by #'order-customer-id)
              (mapcar (lambda (group)
                    (reduce #'+ group :key #'order-total)))
          
          But I prefer the typical Lisp code where I get the sums of the totals
          of the orders with the same customer ID which were placed in the past
          week, instead of the orders made the past week grouped by customer ID
          their totals summed together.
       
          Blikkentrekker wrote 1 day ago:
          I feel languages should just have some kind of sugar or operator for
          this, in fact in Ocaml the |> operator exists where
          
              |> 
             ()
          
          Are just one and the same
          
          For a variadic language you'd need something more involved though.
          But some kind of syntax can probably be invented in some language.
       
            sph wrote 14 hours 19 min ago:
            Elixir has it. To make it worthwhile, the entire standard library
            has to be designed to have the ‘object’ of the function as
            first argument.
            
               [1,2,3]
               |> Enum.map(&square/1)
               |> Enum.filter(&odd?/1)
            
            Using a threading operator where there is no such consistency is
            painful. This is why I dislike CL’s or Python’s map function,
            taking the list to operate on as second argument, instead of first.
            A threading operator wouldn’t be as effective there.
       
              shawn_w wrote 9 hours 7 min ago:
              Taking the object as the last argument works just as well. Just
              needs to be consistent whichever way is chosen.
       
            emidln wrote 1 day ago:
            It's common to write the thrush combinator as a lisp macro. Clojure
            ships ->, ->>, as->, some->, some->>, cond->, and cond->> out of
            the box. You can find similar macros for CL[0], Racket[1], and a
            scheme SRFI[2]. Writing them is a fun exercise in your lisp of
            choice if you don't have a library available.
            
            [0] [1] [2]
            
  HTML      [1]: https://github.com/dtenny/clj-arrows
  HTML      [2]: https://docs.racket-lang.org/threading/index.html
  HTML      [3]: https://srfi.schemers.org/srfi-197/srfi-197.html
       
          evdubs wrote 1 day ago:
          Threading macros are nice, though, right?
          
  HTML    [1]: https://docs.racket-lang.org/threading/introduction.html
       
            matheusmoreira wrote 23 hours 30 min ago:
            Love those.
       
            whartung wrote 1 day ago:
            They're nice, but they're not the same thing.
            
            The threading macros are (as I understand it) pure sugar.
            
            Turning (-> (gather my-list) uppercase-list sort) into (sort
            (uppercase-list (gather my-list))).
            
            In contrast to, say, Java (I can't speak to the code above):
            
                List things = thingIds.stream()
                    .map(model::findThing)
                    .filter(Objects::nonNull)
                    .toList();
            
            These are streamed. This is pretty much a pipe structure, whereas
            the threading macros will create a lot of temporary copies of the
            data (I don't know if that's a universal truth). That is, if you're
            processing a 1000 items, say `gather` returns a 1000 items, that
            1000 item list is passed to `uppercase-list` which return a new
            1000 item list to feed to `sort` which returns another 1000 item
            list (assuming none of these are destructive).
            
            I wish CL had something like the Java streams (maybe it does).
       
              harryposner wrote 23 hours 21 min ago:
              Clojure has two options:
              
              The version with a threading macro, will create a lazy-sequence
              for each step in the pipeline.    It will not instantiate the
              entire list, so it's O(1) memory overhead in terms of peak
              memory, but it churns O(N) extra garbage.
              
                  (->> things
                   (map model/find-thing)
                   (filter some?))
              
              And the version with transducers, which will not create any
              intermediate sequences:
              
                  (sequence (comp (map model/find-thing)
                          (filter some?))
                        things)
              
              It looks like there's a Common Lisp transducers library, but I
              have no idea how widely it's used.
              
  HTML        [1]: https://github.com/fosskers/transducers
       
              kagevf wrote 23 hours 52 min ago:
              Apparently, the Series library offers that. It didn't make it
              into the ANSI standard, but it's still maintained and covered in
              CLtL2.
              
              edit SICP has examples on how to implement streaming (in Scheme).
       
              evdubs wrote 1 day ago:
              I am pretty sure Racket's `stream` will handle this use case.
              
  HTML        [1]: https://docs.racket-lang.org/reference/streams.html
       
        jksmith wrote 1 day ago:
        Now that I'm out of the corporate tyranny and have my own company, I
        use lisp for everything. There's certain satisfaction in writing config
        files and persisting data directly in s-expressions. Any json
        requirements are triggered by exports to foreign systems.
       
          Blikkentrekker wrote 1 day ago:
          That JSON prohibits trailing commata makes it an absolute pain to
          work with in practice.
          
          I also like how in Haskell:
          
             something =
               { element
               , element1
               , element2
               , element3
               }
          
          Is an actually idiomatic way to deal with the lack of trailing
          commata.
       
            chirsz wrote 17 hours 23 min ago:
            Welcome to
            
  HTML      [1]: https://jsonc.org
       
            shawn_w wrote 23 hours 45 min ago:
            You see that style in SQL too.
       
            Ferret7446 wrote 23 hours 56 min ago:
            Not really? A linter/formatter takes care of it.
       
            kazinator wrote 1 day ago:
            I did something like that in C++ circa 1998, before seeing it
            anywhere else:
            
              MyClass::MyClass(foo bar, int arg1, int arg2)
              : Base(bar)
              , member1(arg1)
              , member2(arg2)
              {
              }
       
          atcol wrote 1 day ago:
          Which Lisp, out of interest?
       
            jksmith wrote 17 hours 24 min ago:
            I use the Franz Allegro toolchain exclusively.
       
            iLemming wrote 1 day ago:
            Does it really matter? There's a point in every Lisper's life, a
            threshold after which the question becomes immaterial - you'd stop
            thinking about intricacies of whatever Lisp and focus on the
            platform specifics instead. Any given day I might program in
            three-four different Lisp dialects, e.g. Clojure/Clourescript,
            Fennel, Elisp, Janet, etc. and it practically feels like I'm using
            the same PL. While switching between TS and JS (same family) never
            feels even close - there's always some mental burden.
       
              jasaldivara wrote 14 hours 43 min ago:
              I don't want to be a gatekeeper, but Clojure, Janet and similars
              doesn't even have cons cells; that's hardly 'the same programming
              language'.
       
                tacoda wrote 8 hours 58 min ago:
                I would call these different dialects of Lisp. The data
                doesn’t have to be a function. It’s illustrative. The
                patterns of application still work. What’s the difference if
                delimiters are different or if you are calling JVM libraries?
                The high-level ideas are still right there. Consider
                JavaScript. It is definitely not a Lisp, but if you model it as
                Lisp in C’s clothes, then all of a sudden IIFEs make total
                sense. The point is that it’s a helpful mental model for
                languages other than Lisp.
       
                arunix wrote 10 hours 28 min ago:
                Is the lack of cons cells a significant limitation?
       
                  ux266478 wrote 7 hours 8 min ago:
                  Limitation is the wrong way to think about things when
                  computational equivalence is in play. It's about mental
                  foundation. Lisp at its core is like driving a Turing
                  machine, Clojure is not.
       
              chabska wrote 20 hours 35 min ago:
              If the difference didn't matter, we wouldn't have so many
              different lisps. Obviously the difference mattered enough to the
              people that created Common Lisp when Scheme already existed. Rich
              Hickey thought it mattered when he created a completely new Lisp
              instead of just porting Scheme to the JVM.
       
                veqq wrote 20 hours 17 min ago:
                > If the difference didn't matter, we wouldn't have so many
                different lisps
                
                Literally the opposite. We can make and use so many, because
                writing them is more or less the same. We can quickly throw
                together a new lisp for a new platform or such and use it
                without problem.
       
                  allthetime wrote 15 hours 40 min ago:
                  Why is it necessary to throw together a new lisp and not just
                  use an existing one?
       
                    tacoda wrote 8 hours 56 min ago:
                    Technically when you write in the domain, you are
                    effectively making your own Lisp and then using it. It’s
                    one of the amazing things that macros can do.
       
              andsoitis wrote 22 hours 41 min ago:
              > Does it really matter?
              
              not philosophically, but certainly practically. To double down,
              if all lisps are roughly equivalent from a language POV, then
              you'd want to pick the one or two that will give you the most
              practical advantage (libraries, documentation, dev environment,
              etc.)
       
              arikrahman wrote 1 day ago:
              Even the Lisps have Lisps. Like Clojure with ClojureScript, CLR,
              ClojureDart, Jank... etc.
       
                slifin wrote 14 hours 19 min ago:
                Yes though they're trying to be effectively the same lisp
                
                I do love that I learnt Clojure once like 5-7 years ago and
                more and more dialects keep expanding the choice of runtime I
                can target
       
        evw wrote 1 day ago:
        For folks that want all of this plus macros (and a lot of other great
        things), check out Elixir.
       
          pluralmonad wrote 16 hours 15 min ago:
          Elixir has forever ruined me for other languages. Every new PL I dip
          my toe into gets measured against it. Jose and the core team seem to
          always land on the right decisions, or at least very good ones.
       
          ashton314 wrote 1 day ago:
          100% Elixir is much more a Lisp than Ruby is.
       
            to11mtm wrote 23 hours 36 min ago:
            Agree that Elixir is closer to a Lisp than Ruby.
            
            Heck at least in my brain MLs are closer to a Lisp than Ruby...
       
        danlitt wrote 1 day 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!
       
          matheusmoreira wrote 23 hours 19 min ago:
          Macros depend on homoiconicity which Ruby sacrificed in order to have
          familiar syntax.
       
            ameliaquining wrote 22 hours 27 min ago:
            Homoiconicity makes macros slightly more syntactically elegant, but
            is not at all necessary. Rust has macros and isn't homoiconic at
            all.
       
              matheusmoreira wrote 21 hours 32 min ago:
              C 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 wrote 20 hours 12 min ago:
                C 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 wrote 20 hours 0 min ago:
                  How 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.
       
                    steveklabnik wrote 19 hours 35 min ago:
                    Rust has two form of macros: “macros by example” and
                    “procedural macros.”
                    
                    The latter is basically a function from token streams to
                    token streams, and macros by example are more traditional
                    macros which were initially designed by Dave Herman, who
                    was heavily involved in Racket.
       
                    ameliaquining wrote 19 hours 38 min ago:
                    Yes, 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. [1] 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.
                    
  HTML              [1]: https://doc.rust-lang.org/book/ch20-05-macros.html...
       
                      matheusmoreira wrote 18 hours 26 min ago:
                      > 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
                      
                      That's actually amazing. So the compiler's own data
                      structures are visible in the language.
                      
                      I see how it works now. Thanks for explaining.
       
          shawn_w wrote 23 hours 41 min ago:
          Put the s-expressions back too.
       
          KerrAvon wrote 1 day ago:
          You 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.
       
            bashkiddie wrote 1 day ago:
            > because everything is a method or an object or a closure
            
            well, except for pattern matching. That is just syntax.
       
            yxhuvud wrote 1 day ago:
            Crystal 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.
       
        dismalaf wrote 1 day ago:
        I love Ruby, use it for most of my projects that don't require
        performance.
        
        Nothing I would love more than a Ruby with a Common-Lisp like compiler
        and runtime. Unboxed types, native compilation, partial compilation,
        live image (Ruby has this but "faster Rubies" like Crystal don't),
        etc...
       
          vidarh wrote 23 hours 9 min ago:
          I have a (self-hosted, but buggy and wildly incomplete; don't try to
          use - jRuby or TruffleRuby are better - and far faster - options)
          Ruby compiler that was partly born out of wanting to figure out what
          this would take, and the answer is it is massively painful because
          Ruby has failed to take some basic steps that makes delineating
          read-time and run-time very hard (e.g. you have fun patterns like
          overriding "require", and iterating over directories to decide what
          to require) even though most Ruby programs do have clearly separate
          load and run phases. It's just hard to programmatically separate it.
          
          I still believe you could do pretty well there with a few basic
          "tricks" that could still also remain real/valid Ruby, by recognising
          the most common patterns, documenting them, and providing a way of
          marking exceptions. Combine that with freezing system classes after
          startup as an enabler for various optimization, and a compiler could
          do a pretty good job. But it's a massive piece of work to get it
          right for Ruby.
       
          Syzygies wrote 1 day ago:
          I came close to adopting Scala, many parallels to Ruby with vastly
          better performance.
          
          I'm Ruby or Lean 4.
       
          rjsw wrote 1 day ago:
          ... or just use Common Lisp.
       
            dismalaf wrote 1 day ago:
            Which is what I do.  One can dream though right?  Of a world where
            Ruby stayed just a tad more Lisp-y and less
            Perl/C/Smalltalk/Unix-y.
            
            Also I'm working on a DSL/Macros that give me more Ruby-esque
            quality of life things in Lisp.
       
              tmtvl wrote 22 hours 0 min ago:
              Have you checked out dieggsy's Whisper (< [1] >) yet? It's based
              on Arne Bab's Wisp (SRFI 119).
              
  HTML        [1]: https://sr.ht/~dieggsy/whisper/
       
              ralphc wrote 1 day ago:
              Common Lisp, and even more so Racket, has reader macros. With a
              little help from LLMs you might be able to get a Ruby-like
              language that translates into Lisp.
              
              As a last resort look at Racket's "Rhombus" language, it's
              basically an infix, Python-like syntax on top of Racket. You can
              use that or see how they pull it off and add Ruby constructs to
              it.
       
        DonHopkins wrote 1 day ago:
        What have the Lisps ever done for us?
        
  HTML  [1]: https://www.youtube.com/watch?v=Qc7HmhrgTuQ
       
          BoingBoomTschak wrote 1 day ago:
          Always fun to remind grugs that LISP invented "if" and GC.
       
            wild_egg wrote 20 hours 56 min ago:
            Do you mean blubs?
       
              jonjacky wrote 17 hours 44 min ago:
              Grugs are a different species:
              
  HTML        [1]: https://grugbrain.dev/
       
        pjmlp wrote 1 day ago:
        That is actually Lisp influence on Smalltalk, and Perl, that eventually
        influenced Ruby.
       
          p_l wrote 23 hours 17 min ago:
          Matz directly credits Lisp (through Emacs Lisp) as influence in the
          design of Ruby and its runtime, with Smalltalk influence on the
          language itself, and IIRC Perl as "what was popular and we tried to
          replace"
       
          0xpgm wrote 1 day ago:
          From the article
          
          > Matz has said as much. He’s described Ruby’s design as starting
          from a simple Lisp, stripping out macros and s-expressions, then
          adding an object system, blocks, and Smalltalk-style methods. The
          features most Rubyists fall in love with aren’t the object-oriented
          ones. They’re the functional ones, dressed in friendlier clothes.
       
            wglb wrote 1 day ago:
            But macros and s-expressions are two of my favorites parts of lisp!
       
              dismalaf wrote 1 day ago:
              Funny enough Lisp was originally meant to be written in a higher
              level syntax (with infix operators and everything).
              
              But yeah, macros and S-expressions make it easier to write your
              own DSLs.
       
                pjmlp wrote 1 day ago:
                With decades later, Dylan and Julia becoming the only ones that
                kind of managed to get some adoption doing it.
                
                For better or worse, parenthesis aren't that bad with the
                proper IDE tooling.
       
                  to11mtm wrote 23 hours 25 min ago:
                  > For better or worse, parenthesis aren't that bad with the
                  proper IDE tooling.
                  
                  Hell, even without [0], you can at least count the
                  parenthesis by hand in a pinch. I remember seeing lots of
                  crazy-awesome stuff done in AutoLisp by 'non-programmers',
                  versus 'structure as spacing' in Python which really sucks if
                  the Editor was designed to use the system default (probably
                  non-monospaced, cause other products in the industry had
                  dialogs that broke if you switched to a monospaced) font. [1]
                  
                  [0] - but real talk parenthesis matching in an editor is a
                  lifesaver
                  
                  [1] - oooooold version of a very popular GIS product.
       
          Smalltalker-80 wrote 1 day ago:
          Totalle agree, I just googled it:
          "Yukihiro 'Matz' Matsumoto heavily credits Smalltalk as the deepest
          structural inspiration behind Ruby’s object model. He combined
          Smalltalk’s beautiful object-oriented architecture and
          message-passing system with features from other languages to create a
          tool designed primarily for developer happiness."
          Including the closures and collection operations.
       
            riffraff wrote 1 day ago:
            "Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I
            admit that. But it is nicer to ordinary people."
            
            (Matz speaking at the LL2 conference some 20+ years ago)
       
          dragonwriter wrote 1 day ago:
          No, its actual influence from Lisp-family languages (including
          Scheme). Yes, Lisp also influenced Perl and Smalltalk, but Matz was
          not ignorant of Lisp with the only influence om Ruby from Lisp being
          indirect through those other languages.
       
       
   DIR <- back to front page