
Ask YC: Ruby and Lisp devs, please answer this (Not a flame war) - Readmore
I'm a Ruby guy, I've fallen in love with the language thanks to Rails. I have a Master's in CS and in college we studied mainly Java, along with some Lisp and C, but I try to do all my current programming in Ruby.<p>In an effort to not be a Blub programmer I have taken another look at Lisp to see what I'm missing, but I'm afraid that I can't really see it.  I found this page http://innig.net/software/ruby/closures-in-ruby.rb which explains Closures in Ruby and after looking through that I don't really see what I could do with Lisp that I can't do with Ruby.<p>Again, I'm not looking for a "OMG Python is better than both" I would just like some honest answers about what the differences are. It's always worth it to learn new languages but would it be a better use of my time to start over and learn Lisp or just learn how to proficiently use Closures in Ruby?<p>Any comments, questions, etc. would be appreciated.
======
damon
Ruby descended from lisp, according to matz. So in order to "see what you're
missing" by using ruby, take a look at what he removed or changed from lisp.
In particular he removed macros and created syntax. As others have commented,
macros are a _very_ powerful language feature.

[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-
talk/...](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/179642)

------
mnemonicsloth
1\. CLOS and the MOP have some very devoted advocates, and it's obvious that
CL's object model contains a strict superset of the behaviors available in
other languages. If you don't absolutely hate OOP, they're worth checking out
[1].

2\. Macros. Macros, macros, macros. Commonplaces like "code is data" and
"program-writing programs" are useful characterizations, but they make it easy
to underestimate how much of a productivity booster metaprogramming can be.

Despite regular practice and a lot of first-rate reading material, I stayed
clueless about macrology until I got stuck with a big ugly infrastructure
problem [2] that forced me to use a bottom-up style. At some point I
macroexpanded my code out of curiosity and found myself staring at pages and
pages of boilerplate. Some of it -- database code in particular -- even
reminded me of stuff I previously would have done by hand.

Anyway, I guess I recommend the Kool Aid...

[1] OOP owes me my Freshman and Sophomore years.

[2] I was building a platform, but I can't talk about it.

------
brlewis
It's not that there's something you can do in Lisp that absolutely can't be
done in Ruby. It's just that it's more convenient in Lisp, e.g. real closures
instead of seven or eight closure-like constructs.

I took a look at that Closures in Ruby page you mentioned.

It says about Ruby: "This is quite a dizzing array of syntactic options, with
subtle semantics differences that are not at all obvious, and riddled with
minor special cases. It's like a big bear trap from programmers who expect the
language to just work."

~~~
Zak
Ruby has real closures with semantics similar to Lisp: lambda expressions that
reference variables from their enclosing lexical scope. It also has a number
of constructs that create closures implicitly, and some others that may or may
not be implemented that way, but you're not required to use them. You can use
closures just like you would in Lisp.

------
jimbokun
Here's a good comparison:

[http://markwatson.com/blog/2008/01/cool-common-lisp-
elephant...](http://markwatson.com/blog/2008/01/cool-common-lisp-elephant-
object.html)

Performance is a big difference:

"Common Lisp compiled code runs much faster than Ruby: typical benchmark
results are about 30 times faster - but Ruby's slowness is mitigated if a lot
of processing is performed in native libraries like Ferret."

I don't think Ruby has all of the functionality of CLOS or the Meta Object
Protocol. Here's Matz commenting on the lack of multi-methods in Ruby:

[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-
talk/...](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/49964)

"Most OO langauge includes Ruby see methods as "element of an object" This
does not hold for CLOS. You loose the tight relationship but gain a new level
of flexibility."

Beyond that, I would say pick a programming methodology and there is probably
a CL implementation of it somewhere out there built with macros. That's due to
the greater maturity of CL and "real macros" (which have been well covered by
others already). And beyond macros, the "code as data" paradigm enabled by
s-expressions has other uses (I think Steve Yegge mentioned "executable log
files" as an example).

------
enigman
In theory, it should be possible to get better performance out of a Lisp
application, since most versions of Common Lisp include a compiler. Ruby is
interpreted at present and can be slower in some contexts. Runtime pauses for
garbage collection can be quite noticeable in Ruby.

------
dag
The main difference is that Lisp has macros, no other languages' macro systems
come close.

For the cute version of why Lisp macros are so awesome check out chapter 8 of
Practical Common Lisp (<http://gigamonkeys.com/book/>).

For the serious and intense version check out On Lisp
(<http://paulgraham.com/onlisptext.html>).

------
apgwoz
Your likely to get many comments about macros, so I suggest you take a closer
look at what macros actually can do for you. That should be a sufficient
enough reason to take a closer look at Lisp (be it Common Lisp or Scheme).

~~~
Todd
That's it, in a nutshell. The macro facility is what differentiates Lisp from
other dynamic languages that have, seemingly, all of the same attributes--
dynamic/lexical scope, closures, etc.

They allow you to write a true DSL. Paul Graham pretty much wrote the book on
the subject (On Lisp) which he graciously offers as a free download since it's
out of print.

~~~
pg
As a data point, in the source code of Arc and its libraries + the web server
+ News.YC + all of YC's internal applications, there are 738 calls to def (=
CL defun) and 187 calls to mac (= CL defmacro). This isn't a complete list,
because there are other defining operators, but it gives you an idea how large
a role macros play in a typical Lisp application.

If you measured by uses of each type of operator, the role of macros would be
even larger. You often write a function that you only call once, but you
wouldn't do that with a macro.

Here's the last piece of code I wrote. I wrote it because I was curious to see
what colors users had chosen for the top bar.

    
    
      (defopa topcolors req
        (minipage "Topcolors"
          (tab
            (each user (sort (compare > [karma _])
                             (keep [aand (uvar _ topcolor)
                                         (isnt it (hexrep orange))] 
                                   (keys profs*)))
              (tr (td (link user (user-url user)))
                  (tdcolor (hex>color (uvar user topcolor)) (hspace 30)))))))
    

There are 10 macros used here: defopa, minipage, tab, each, karma, aand, uvar,
tr, td, tdcolor.

Actually it's a hack that karma is a macro. I wanted it to be settable and was
too lazy to define a setter, so I just defined it as a macro. It should be a
function, and I should be able to say just (compare > karma).

~~~
Tichy
I thought that Arc is written in Scheme, not in Common Lisp? Are Scheme Macros
equally powerful?

Edit: OK, perhaps Arc is written in Scheme, but Arc itself features CL like
macros, that would explain it ;-)

~~~
pg
Arc is written in Scheme in the sense that it compiles into Scheme, and uses
the Scheme read, numbers, etc. But Arc macros are not Scheme macros.

------
tx
All other Lisp-inspired languages, including Ruby, have added one important
feature by introducing their biggest restriction: they went with more complex
syntax abandoning Lisp's S-expressions. By doing so, they have created a
substantial difference in how code and data are represented: whereas in Lisp
everything, including your code, can be treated as data.

This is, in my humble opinion, the biggest difference between Lisp and others.

------
kyle-burton
Other features that have piqued my interest (besides the already mentioned,
and vitally important, macros) are:

\- conditoins and restarts \- CLOS \- reader macros (which are distinctly
different from normal macros).

If you're talking about other Lisps (besides CL), like Scheme, it's worth
looking at define-syntax and syntax-rules and how they deal with some of the
intricacies of creating macros with define-macro.

------
nickb
Try RLisp, <http://chaosforge.org/taw/rlisp/>

"RLisp is a Lisp dialect naturally embedded in Ruby"

------
vikram
From the Ruby side the difference is the quantity and quality of libraries
that are available. You are likely to find stuff that is currently been worked
on, with CL this can be a real problem. There are a lot of half done
libraries, so you have to be willing to read a lot of code, either make
improvements yourself or write some from scratch.

------
db4n
Macros can be used to automate function definition. You can't use blocks and
HOFs for that, because definition occurs at compile time. You can also
automate definition of other macros.

<http://paste.lisp.org/display/54227>

------
stefan_tilkov
I know that Ruby's metaprogramming facilities don't equal Lisp's, but does
that matter in practice? i.e. is there a convincing number of metaprogramming
use cases that can be implemented using Lisp macros, but can't be implemented
using the Ruby meta object protocol?

------
gregwebs
There is another facility ruby and lisp lack- a good typing system- which you
can find in languages like Haskell.

~~~
Tichy
I stopped reading the Haskell tutorial when I came to the part where arrays
have to be homogeneous (or something like that, basically all elements in the
array have to have the same type, if I remember correctly). That is one of the
things that is most annoying in Java, so why put up with it in another
language?

In a similar vein, I wonder about the Erlang hype - some things are really
impractical to do in Erlang, for lack of syntactic sugar and the immutable
memory constraint. People were always bickering about the constraints in Java
(no multiple inheritance and stuff like that), so why choose another language
with impractical constraints instead?

~~~
jfoutz
This is a little tricky, Types can be pretty broad. First, you could define a
tree type with all sorts of different leaves, you could have a list of tree
parts, something like:

Tree = Branch Tree Tree | ILeaf Int | SLeaf String

then a list like [ILeaf 1, SLeaf "foo"]. Another way to go takes advantage of
type erasure. Currently it's just a popular extension but it lets you have
lists of stuff in the same type class.

A good example is "Show" you can have a list off stuff that knows how to turn
itself into strings. always a handy thing.

Basically you get the big two, group things based on what they are, or group
things based on what you can do to them.

Perhaps there is a big pile of random stuff you want to hang on to, but i'd
bet 99.9% of the time you really want to collect the stuff into a coherent
type.

