Gray Soft

The programming blog of James Edward Gray II (JEG2).
  • 4

    JAN
    2008

    Dave Thomas is Definitely the Sammy Sosa of Programming

    There is a debate raging in the Ruby community that I don't want any part of. I'm not going to engage in any of the mud slinging and there will be no debate here. Commenters have been warned. What I do want to do is to share some simple uncontested facts about a man I am lucky enough to know.

    Sammy Sosa is famous for one thing: hitting home runs. In the entire history of the game of baseball five players have managed to hit over 600 home runs and Sammy is one of them. If that wasn't amazing enough, he has hit at least one home run against every single Major League team and in 44 Major League ballparks. Baseball fans everywhere love to watch Sammy Sosa at bat.

    Now if I had to name five programmers who get me as excited about programming as Sammy Sosa does about baseball, Dave Thomas would definitely make the list. Dave does exactly what Sammy always does: continually preforms the hardest tasks of his profession while making it look easy to the fans. Allow me to give a few examples.

    Read more…

  • 2

    JAN
    2008

    Getting FasterCSV Ready for Ruby 1.9

    The call came down from on high just before the Ruby 1.9 release: replace the standard csv.rb library with faster_csv.rb. With only hours to make the change it was a little harder than I expected. The FasterCSV code base was pretty vanilla Ruby, but it required more work than I would have guessed to get running on Ruby 1.9. Let me share a few of the tips I learned while doctoring the code in the hope that it will help others get their code ready for Ruby 1.9.

    Ruby's String Class Grows Up

    One of the biggest changes in Ruby 1.9 is the addition of m17n (multilingualization). This means that Ruby's Strings are now encoding aware and we must clarify in our code if we are working with bytes, characters, or lines.

    This is a good change, but the odds are that most of us have lazily used the old way to our advantage in the past. If you've ever written code like:

    lines = str.to_a
    

    you have bad habits to break. I sure did. Under Ruby 1.9 that code would translate to:

    lines = str.lines.to_a
    

    Read more…

  • 18

    NOV
    2007

    Ghost Wheel Example

    There has been a fair bit of buzz around the Treetop parser in the Ruby community lately. Part of that is fueled by the nice screencast that shows off how to use the parser generator.

    It doesn't get talked about as much, but I wrote a parser generator too, called Ghost Wheel. Probably the main reason Ghost Wheel doesn't receive much attention yet is that I have been slow in getting the documentation written. Given that, I thought I would show how the code built in the Treetop screencast translates to Ghost Wheel:

    #!/usr/bin/env ruby -wKU
    
    require "rubygems"
    require "ghost_wheel"
    
    # define a parser using Ghost Wheel's Ruby DSL
    RubyParser    = GhostWheel.build_parser do
      rule( :additive,
            alt( seq( :multiplicative,
                      :space,
                      :additive_op,
                      :space,
                      :additive ) { |add| add[0].send(add[2], add[-1])},
                 :multiplicative ) )
      rule(:additive_op, alt("+", "-"))
    
      rule( :multiplicative,
            alt( seq( :primary,
                      :space,
                      :multiplicative_op,
                      :space,
                      :multiplicative ) { |mul| mul[0].send(mul[2], mul[-1])},
                 :primary ) )
      rule(:multiplicative_op, alt("*", "/"))
    
      rule(:primary, alt(:parenthized_additive, :number))
      rule( :parenthized_additive,
            seq("(", :space, :additive, :space, ")") { |par| par[2] } )
      rule(:number, /[1-9][0-9]*|0/) { |n| Integer(n) }
    
      rule(:space, /\s*/)
      parser(:exp, seq(:additive, eof) { |e| e[0] })
    end
    
    # define a parser using Ghost Wheel's grammar syntax
    GrammarParser = GhostWheel.build_parser %q{
      additive             =  multiplicative space additive_op space additive
                              { ast[0].send(ast[2], ast[-1]) }
                           |  multiplicative
      additive_op          =  "+" | "-"
    
      multiplicative       =  primary space multiplicative_op space multiplicative
                              { ast[0].send(ast[2], ast[-1])}
                           |  primary
      multiplicative_op    =  "*" | "/"
    
      primary              = parenthized_additive | number
      parenthized_additive =  "(" space additive space ")" { ast[2] }
      number               =  /[1-9][0-9]*|0/ { Integer(ast) }
    
      space                =  /\s*/
      exp                  := additive EOF { ast[0] }
    }
    
    if __FILE__ == $PROGRAM_NAME
      require "test/unit"
    
      class TestArithmetic < Test::Unit::TestCase
        def test_paring_numbers
          assert_parses         "0"
          assert_parses         "1"
          assert_parses         "123"
          assert_does_not_parse "01"
        end
    
        def test_parsing_multiplicative
          assert_parses "1*2"
          assert_parses "1 * 2"
          assert_parses "1/2"
          assert_parses "1 / 2"
        end
    
        def test_parsing_additive
          assert_parses "1+2"
          assert_parses "1 + 2"
          assert_parses "1-2"
          assert_parses "1 - 2"
    
          assert_parses "1*2 + 3 * 4"
        end
    
        def test_parsing_parenthized_expressions
          assert_parses "1 * (2 + 3) * 4"
        end
    
        def test_parse_results
          assert_correct_result "0"
          assert_correct_result "1"
          assert_correct_result "123"
    
          assert_correct_result "1*2"
          assert_correct_result "1 * 2"
          assert_correct_result "1/2"
          assert_correct_result "1 / 2"
    
          assert_correct_result "1+2"
          assert_correct_result "1 + 2"
          assert_correct_result "1-2"
          assert_correct_result "1 - 2"
    
          assert_correct_result "1*2 + 3 * 4"
          assert_correct_result "1 * (2 + 3) * 4"
        end
    
        private
    
        PARSERS = [RubyParser, GrammarParser]
    
        def assert_parses(input)
          PARSERS.each do |parser|
            assert_nothing_raised(GhostWheel::FailedParseError) do
              parser.parse(input)
            end
          end
        end
    
        def assert_does_not_parse(input)
          PARSERS.each do |parser|
            assert_raises(GhostWheel::FailedParseError) { parser.parse(input) }
          end
        end
    
        def assert_correct_result(input)
          PARSERS.each { |parser| assert_equal(eval(input), parser.parse(input)) }
        end
      end
    end
    

    Read more…

  • 10

    SEP
    2007

    I Enjoy the Regional Conferences

    I have to say that the Lone Star Rubyconf was just great. I'm hoping that's representative of the other regional Ruby conferences as well and from what I've heard it is.

    I was at the official Rubyconf last year and I'm comfortable saying that the Lone Star Rubyconf competed well on content. We had great keynotes from Charles Nutter and Zed Shaw (though he's wrong about that don't love your language point); we had presentations from icons of the community, like Hal Fulton; we had popular topics covered by the experts, like the RSpec presentation from Mr. RSpec, David Chelimsky; and we had the wonderfully practical technical talks, like Evan Short's smooth coverage of Domain Specific Languages.

    While you do have to consider it a small minus to miss seeing Matz and a few other key Rubyists, the conference countered with a terrific small community feel. Everyone was open and friendly. You could easily approach anyone and chat them up about nearly any topic. Several people approached me and I loved it.

    Read more…

  • 8

    SEP
    2007

    I Got Booed at the LSRC!

    At the Lone Star Rubyconf, only a single speech coaxed a "Boo!" out crowd. Of course, it was mine.

    On a slide where I was trying to counter the expert warnings against using glue code features in Ruby, I told people not to lose a lot of sleep about external dependencies. When I added the comment, "That's your SysAdmin problem anyway," one audience member growled a complaint.

    The complainer later apologized to me for the outburst, but his point was valid that I didn't say what I intended to say.

    What I was trying to get across is that any external dependency I add to an application is going to become a line item in my SysAdmin's build script. After that, neither of us will lose any more sleep over it. He does his job so well that it makes mine easy. So, what came off as an insult, was intended as a compliment. I apologize.

    To rebalance the global karma pool, do me a favor and hug your SysAdmin today.

  • 7

    SEP
    2007

    Marcel at Play

    At the preconference charity event for the first Lone Star Rubyconf, Marcel Molina, Jr gave one of the best talks I've ever heard at a conference. The entire talk was Marcel showing examples of pathological (his word, not mine) Ruby code. Not only did he show all these examples to a room full of people new to language at an event titled Intro to Ruby, but he actually made a case for these examples being proof positive Ruby is a reliable language.

    This was a very unique approach to speeches in that we literally saw a Ruby master at play. While most speakers try to put our best foot forward, Marcel embraced the craziness and just had some fun. His attitude was infectious and really drove his point home.

    We should all try to have more fun with our speeches. It's so enlightening to watch, for any audience. I hope I have the courage to try a similar talk in the future.

    In: My Heroes | Tags: For Fun | 3 Comments
  • 23

    AUG
    2007

    Finding Serenity

    [Update: This blog no longer runs on Serenity. I've created yet another engine to power it.]

    I'll be nice and not name any names, but my old blog software was really struggling. I've dealt with numerous issues from it over the years I've run this blog and all of that extra maintenance finally wore me down.

    I'm sure you've noticed the theme change here by now. That's the surface result of me having replaced the entire backend. This blog now runs on a blogging engine I invented called Serenity. It's a young engine at this point, but I suspect it will improve as I fiddle with it and find what I like.

    I've moved all of the content over, so my hope is that nothing is missing. Unfortunately there have been some URL changes. I apologize for that and promise that I don't plan to change them again anytime in the near future.

    Thanks for being patient with me during this transition. I hope that it will lighten my maintenance load and give me more time to write articles.

  • 13

    AUG
    2007

    Erlang Message Passing

    Like many Pragmatic Programmer fans, I've been having a look at Erlang recently by working my way through Programming Erlang. In the book, the author includes a challenge: build a message ring of processes of size M and send a message around the ring N times, timing how long this takes. The author also suggests doing this in other languages and comparing the results. Having now done this, I can tell you that it is an interesting exercise.

    First, the Erlang results. Here's a sample run that creates 30,000 processes and sends a message around that ring 1,000 times:

    $ erl -noshell -s solution start 30000 1000
    Creating 30000 processes (32768 allowed)...
    Done.
    Timer started.
    Sending a message around the ring 1000 times...
    Done:  success
    Time in seconds:  29
    

    So we see about 30,000,000 message passes there in roughly 30 seconds. I should also note that Erlang creates those processes very, very fast. It's possible to raise the process limit shown there, but I'm more interested in comparing what these languages can do out of the box.

    Read more…

  • 3

    AUG
    2007

    The Ruby VM: Episode V

    You have told us before that one of the big reasons to move to a new Ruby VM was to provide new options for optimization. Can you talk a little about the optimizations you have added to the new Ruby VM thus far and what operations will likely be faster because of them?

    ko1:

    OK. At first, I write about basic of YARV instruction. YARV has two type instructions. First is primitive instruction. It's as written, primitive. Ruby code can be represented in these primitive instruction. Second is instructions for optimization. It's not needed to represent Ruby scripts, but they are added for optimization. Primitive instructions doesn't include _ in their name (like putobject), and optimize instructions do (like opt_plus). This policy helps you if you want to see VM instructions. Initially, you need to read primitive instructions.

    The most easy and effective optimization is Specialized Instructions. This optimization replace method call with another VM instruction, such as Fixnum#+ to opt_plus. Current Ruby's numeric calculation is slow because all operations are method call. For example, 1 + 2 means 1.+(2). But numeric operations are more lightweight than Ruby's method invocation. So method call is only overhead for numeric operation. Specialized Instructions allow the VM to skip method call overhead.

    But we can't know which expression is numeric operation or not at compile time. See this expression: a = c ? 1 : [:elem], a will be Fixnum or Array at runtime.

    So, we can't replace + expression with numeric operation instruction. Specialized Instruction, for example opt_plus which is replaced with + method invocation will do following code:

    def opt_plus(recv, val) # simple version
       if recv.class == Fixnum && val.class == Fixnum
         if Fixnum#+ is not redefined
           return calculate "recv + val" without method call
         end
       end
       # normal method invocation
       recv.+(val)
    end
    

    Check receiver and value are Fixnum or not, and check Fixnum#+ are not redefined. After these check, calculate them without method invocation. In fact, Float#+ are also checked. There are other specialized instructions.

    YARV eases to implement such instructions with VM generator. You shouldn't write bothersome code such as stack manipulation. If you write VM instruction such as opt_plus in simple VM DSL, VM generator will translate it to C code.

    Specialized Instruction is very simple, but effective for simple benchmark such as fib() or tak() and some calculate bound program.

    Read more…

  • 13

    JUL
    2007

    The Ruby VM: Episode IV

    We've talked about threads, so let's talk a little about character encodings. This is another big change planned for Ruby's future. Matz, you have stated that you plan to add m17n (multilingualization) support to Ruby. Can you talk a little about what that change actually means for Ruby users?

    Matz:

    Nothing much, except for some incompatibility in string manipulation, for example, "abc"[0] will give "a" instead of 97, and string indexing will be based on character instead of byte. I guess the biggest difference is that we can officially declare we support Unicode. ;-)

    Unlike Perl nor Python, Ruby's M17N is not Unicode based (Universal Character Set or USC). It's character set independent (CSI). It will handle Unicode, along with other encoding schemes such as ISO8859 or EUC-JP etc. without converting them into Unicode.

    Some misunderstand our motivation. We are no Unicode haters. Rather, I'd love to use Unicode if situation allows. We hate conversion between character sets. For historical reasons, there are many variety of character sets. For example, Shift_JIS character set has at least 5 variations, which differ each other in a few characters mapping. Unfortunately, we have no way to distinguish them. Thus conversion may cause information loss. If a language provide Unicode centric text manipulation, there's no way to avoid the problem, as long as we use that language.

    ko1:

    On my policy, I escape from this topic :)

    Read more…