Early experiments with JRuby

I’ve made no secret on this blog that I am fond of Ruby, and that I find Java rather verbose and awkward.  But at the same time, I realise you can’t deny the commercial importance and ubiquity of Java.  I’ve been hoping to find a way to combine the stronger points of both languages, and of course JRuby gives me just what I need.

So I’ve been experimenting with it for the last few days, and I like what I see.

For example, whereas in vanilla Ruby you might write:

def qsort(a)
return a if a.length <= 1
pivot = a.delete_at rand(a.length)
return (qsort(a.select { |x| x <= pivot }) +
[ pivot ] +
qsort(a.select { |x| x > pivot }))
end

In JRuby, you simply write:

jrequire ‘java.lang.Jruby.*’
jrequire ‘java.lang.util.ArrayList’
def public ArrayList<T> qsort<T> (theArray is ArrayList<T>)
if Arrays.lengthOfArray(theArray) <= 1
return theArray
end

theRandomInteger = RandomIntegers.rand(theArray.length)
pivot = Arrays.elementAtIndex(theArray, theRandomInteger)
Array.deleteElementAtIndex(theArray, theRandomInteger)

lowerTemporaryArray = ArrayList<T>.new
Iterator<T> iter = theArray.iterator()
while iter.hasNext()
theValue = iter.next
if theValue <= pivot
lowerTemporaryArray.append(theValue)
end
end
lowerTemporaryArray = qsort(lowerTemporaryArray)

upperTemporaryArray = ArrayList<T>.new
iter = theArray.iterator()
while iter.hasNext()
theValue = iter.next
if theValue > pivot
upperTemporaryArray.append(theValue)
end
end
upperTemporaryArray = qsort(upperTemporaryArray)

resultArray = ArrayList<T>
Arrays.appendElementsOfArray(resultArray, lowerTemporaryArray)
Arrays.appendSingleElement(resultArray, pivot)
Arrays.appendElementsOfArray(resultArray, upperTemporaryArray)

return resultArray
end

It’s an important step forward.  I think I’m going to be using it a lot.

About these ads

20 responses to “Early experiments with JRuby

  1. !slooF lirpA

  2. Hahaha. This blog is rapidly becoming a must-read for me. Keep’em coming !

  3. Can you do that in Enterprise Cobolscript?

  4. It’s definitely a step forward! The second version looks pretty professional. You should try adding design patterns, all of them.

  5. You are going places in my head that don’t have reliable fire departments.

    from random import choice

    def qsort( a ):

    ….if len(a) <= 1: return a

    ….pivot = choice( a )

    ….return qsort( [ x for x in a if x < pivot ] ) +

    ………………….[ x for x in a if x == pivot ] ) +

    ………..qsort( [ x for x in a if x > pivot ] )

  6. Robin Jubber

    Is this satire? I know nothing of these languages so I’m probably missing the joke. Surely the shorter code is better than the longer code?

    Cheers

    A Game Programmer.

  7. Joao Assuncao

    You are looking at the wrong language.
    Groovy version of qsort:
    static def quicksort(v) {
    if (v == null || v.size <= 1) return v
    def (less, more) = v[1..-1].split { it <= v[0] }
    return quicksort(less) + v[0] + quicksort(more)
    }

    With groovy you can benefit from both worlds. Not only you can use all the existing Java libraries but you can also use groovy classes in Java.

  8. Robin,

    One might wonder if what YOU write is satire or sarcasm as well :-) It’s always difficult to tell with just letters. In any case – today is April Fool’s day.

    The Ruby version is very short and elegant, but it does incorporate something I hate to see in any language no matter how small or large the construct, and it’s what I call “ASCII art syntax”. The syntax I’m talking about is “{ |x| x <= pivot })".

    To anyone programming Ruby it's probably short, elegant and obvious (obviously). To someone not familiar it's a mash of random characters, even if you should be able to make sense of it by looking at the context.

    The question is if you can remove ASCII art syntax from popular and powerful languages without making them overly verbose.

    If I were to avoid this syntax at all costs I'd probably be left with no choice other than Apple Script.

  9. Joao, the Groovy version does look nice, but it has a bug — what happens when the array contains two or more identical values?

    Robert, I take your point on ASCII-art syntax — I guess you are not a big Lisp fan — but, yes, there is a tradeoff between concision and readability to the uninitiated. In the case of Ruby blocks, you can have it the way you want by using do…end rather than {…} to mark the block, so:

    do |x| x <= pivot end

    But I think this is a case where it’s worth investing the ten minutes to just go ahead and learn the syntax. For short blocks, {…} is more idiomatic.

    And don’t forget that the alternative to ASCII-art syntax is keyword soup. Yes, there should be a happy medium somewhere between @{$a[$i]} and public static final transient volatile synchronized Integer theTemporaryLoopCounter; we’re trying to land squarely in that middle ground.

  10. Haha, you made my day :-D

  11. Scott O'Dell

    Here’s a quick sort in Lisp if you want some practice counting parentheses.

    (defun qsort (lis &optional (less nil) (greater nil))
    (cond ((null lis) nil)
    ((null (cdr lis)) (append (qsort less) (cons (car lis) (qsort greater))))
    (t (let ( (pivot (car lis)) (x (cadr lis)))
    (if (<= x pivot)
    (qsort (cons pivot (cddr lis)) (cons x less) greater)
    (qsort (cons pivot (cddr lis)) less (cons x greater)))))))

  12. Scott,

    Your Lisp version is nice, but not ready for the Enterprise.

  13. Just for the benefit of those who may not be familiar with JRuby on in on the joke, the Ruby code works in JRuby as written.

  14. Pingback: Chipping the web: April 5th -- Chip's Quips

  15. Here’s the lisp version above, translated into xml. I think it is quite enterprise ready, and possibly even scalable with the right bean technology and ORM application dynamic interfaces.

    http://gist.github.com/358191

    <xml>
      <defun name=”qsort”>
        <args>
          <required-arg name=”lis” />
          <optional-args>
            <optional-arg name=”less” default=”nil”/>
            <optional-arg name=”greater” default=”nil”/>
          </optional-args>
        </args>
        <cond>
          <cond-clause>
            <cond-check>
              <null-check>
                <lis />
              </null-check>
            </cond-check>
            <cond-expr>
              <nil />
            </cond-expr>
          </cond-clause>
          <cond-clause>
            <cond-check>
              <null-check>
                <cdr>
                  <lis />
                </cdr>
              </null-check>
            </cond-check>
            <cond-expr>
              <append>
                <qsort>
                  <less/>
                </qsort>
                <cons>
                  <car>
                    <lis />
                  </car>
                  <qsort>
                    <greater/>
                  </qsort>
                </cons>
              </append>
            </cond-expr>
          </cond-clause>
          <cond-clause>
            <check>
              <true />
            </check>
          </cond-clause>
          <cond-expr>
            <let>
              <let-binding>
                <symbol name=”pivot”>
                  <car>
                    <lis/>
                  </car>
                </symbol>
                <symbol name=”x”>
                  <cadr>
                    <lis/>
                  </cadr>
                </symbol>
              </let-binding>
              <let-body>
                <if>
                  <if-check>
                    <greater-than-or-equal-to>
                      <x/>
                      <pivot/>
                    </greater-than-or-equal-to>
                  </if-check>
                  <if-body>
                    <then-clause>
                      <qsort>
                        <cons>
                          <pivot/>
                          <cddr>
                            <lis/>
                          </cddr>
                        </cons>
                        <cons>
                          <x/>
                          <less/>
                        </cons>
                        <greater/>
                      </qsort>
                    </then-clause>
                    <else-clause>
                      <qsort>
                        <cons>
                          <pivot/>
                          <cddr>
                            <lis/>
                          </cddr>
                        </cons>
                        <less/>
                        <cons>
                          <x/>
                          <greater/>
                        </cons>
                      </qsort>
                    </else-clause>
                  </if-body>
                </if>
              </let-body>
            </let>
          </cond-expr>
        </cond>
      </defun>
    </xml>

  16. Tom,

    This is much better, but it doesn’t have an Abstract Factory, nor make use of the Facade Decorator pattern, and it doesn’t provide any public-visibility getters and setters. That’s before we even start talking about the lamentably primitive threading model you’ve used.

    I fear you may not have what it takes to be a Head-Rush Agile Enterprise Scrum-Master Architect.

  17. Scott O'Dell

    Thank you Tom,

    I’m afraid I was too focused on creating a straight-forward, easily understood algorithm; the maintainability of your version is clearly superior.

    However, I can’t help but think the project could be split into more files. I’d love to start from scratch, but I’ll be in the Validation, Deployment, and Maintenance phases for the next 8 years.

  18. Pingback: The Funniest April Fool’s Joke of This Year « I like stuff.

  19. Thanks Mike, I needed this as my day job demands c++ but my project/startup I’m free to Ruby my way through.

    Of course I’d love my Ruby code to run as fast as numerical processing in c++…then I could merge both worlds :D. JRuby could be the solution (not the “longer” version ;)

  20. I know this started as satire, but looking at that last comment – surely there has to be some room in taking the MacRuby/LLVM combination and getting it to work with the GnuStep/Etoile ObjC runtime, to make a more portable compiled Ruby?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s