Learning Ruby, was a C geek...

Discussion in 'Ruby' started by Nicholas Paul Johnson, Apr 3, 2004.

  1. Hello all,

    As I'm learning Ruby, I've decided to write a few programs in Ruby to get
    a feel for the language.

    I've been a C programmer for a long time. As such, I worry that I'm
    thinking too much like a C programmer, and not like a Ruby programmer...

    My first attempt has been an emulator for a cs-toy processor called IBCM
    (itty-bitty computing machine). Its spec (only 5 pages) is available at:
    http://www.cs.virginia.edu/~cs216/notes/ibcm-poo.pdf

    I've written it, and it works correctly when compared to my program
    written in C, but at its core is a large case-when-end statement.
    This is not `sexy.' I was wondering if there was a better way to do
    this in Ruby, or if I'm just missing the point.

    My code is at: http://manjac.ath.cx/nick/ruby-ibcm.rb

    Thanks all,
    --
    Nicholas Paul Johnson
    nickjohnsonSPAM^H^H^H^
    http://manjac.ath.cx/nick
    _
    ( ) ascii ribbon campaign - against html mail
    X - against microsoft attachments
    / \ http://www.google.com/search?q=ascii ribbon
    --
    Nicholas Paul Johnson, Apr 3, 2004
    #1
    1. Advertising

  2. Nicholas Paul Johnson

    Chris Dutton Guest

    A few suggestions, if I may.

    I wonder if your option detection might be more efficient as:

    trace = true if ARGV.include? "-t"
    dump = true if ARGV.include? "-d"
    filenames = ARGV.delete_if { |n| n !~ /^[^-]/ }
    fn = filenames.empty? ? nil : filenames.first

    It would save you from looping through ARGV, just in case it's a mile
    long or something. :)
    Chris Dutton, Apr 3, 2004
    #2
    1. Advertising

  3. Nicholas Paul Johnson

    Asim Jalis Guest

    On Sat, Apr 03, 2004 at 09:19:19AM +0900, Chris Dutton wrote:
    > A few suggestions, if I may.
    >
    > I wonder if your option detection might be more efficient as:
    >
    > trace = true if ARGV.include? "-t"
    > dump = true if ARGV.include? "-d"
    > filenames = ARGV.delete_if { |n| n !~ /^[^-]/ }
    > fn = filenames.empty? ? nil : filenames.first
    >
    > It would save you from looping through ARGV, just in case it's
    > a mile long or something. :)


    Another suggestion would be to remove the trace statements, which
    clutter up the code. Instead use unit tests to ensure correctness.


    Asim
    Asim Jalis, Apr 3, 2004
    #3
  4. Received: Sat, 3 Apr 2004 08:37:54 +0900
    And lo, Nicholas wrote:

    > I've written it, and it works correctly when compared to my program
    > written in C, but at its core is a large case-when-end statement.
    > This is not `sexy.' I was wondering if there was a better way to do
    > this in Ruby, or if I'm just missing the point.


    This is a project similar in scope to an NES emulator I've written in C. When doing so, I tried and benchmarked 2 situations:

    switch (opcode) {
    case 0x01:
    case 0x02 ... (etc, for every opcode)
    }

    And:
    typedef void (*operand)(address);
    operand opcodes[0x100]; (You'd use 0x10)
    op_0x01(int address) { ... }
    opcodes[0x01] = op_0x01.
    Then call using: opcodes[0x01](addr);

    Ruby caters to the second style rather well, adding in lambda blocks.

    ops = []
    ops[0x01] = lambda { /* incrememnt accum 1 */ |address| Cpu.accum += 1 }

    Either a hash or an array could do the job.

    You'd really just need to fetch op[instruction byte 1 >> 4], if I'm reading that specs document correctly.

    Hope that helps

    - Greg Millam
    Gregory Millam, Apr 3, 2004
    #4
  5. Nicholas Paul Johnson

    daz Guest

    Nicholas Paul Johnson wrote:
    > Hello all,
    >
    > As I'm learning Ruby, I've decided to write a few programs in Ruby to get
    > a feel for the language.
    >
    > I've been a C programmer for a long time. As such, I worry that I'm
    > thinking too much like a C programmer, and not like a Ruby programmer...
    >
    > I've written it, and it works correctly when compared to my program
    > written in C, but at its core is a large case-when-end statement.
    > This is not 'sexy'.
    >


    Hi Nicholas,

    Technically, case isn't as sexy in Ruby as switch is in C, but I think
    many Rubyists would use it the way you have done in this example.

    The rest of your code suggests to me that you are on the correct path.

    Welcome here !


    daz
    daz, Apr 3, 2004
    #5
  6. Received: Sat, 3 Apr 2004 15:26:46 +0900
    And lo, Nicholas wrote:

    > While were on the subject, what is technically the difference between some
    > block, such as { |n| 1+n }, and the corresponding lambda { |n| 1+n }, or
    > more specifically, how does the interpreter treat them differently? Also,
    > could I assign a lambda to a variable as I would in scheme to create a
    > function?


    They're the same thing. The following two are identical

    myproc = lambda { |n| 1+n }
    mymethod("5",lambda)

    mymethod("5") { |n| 1+n }

    You could then call
    myproc.call("4") #-> 5

    So to continue with the opcode hash example
    op[0x05] = lambda { |addr| ... }
    op[0x05].call(address)

    the 'lambda' is needed to let ruby know it's defining a Proc object.

    c = { |n| 1+n } - doesn't really make sense.

    'proc' is an alias for lambda, but I believe it's to be phased out because of proc/Proc confusin. and lambda is really just "Proc.new"

    c = Proc.new { |n| 1+n }

    These blocks, with 'yield,' are among my favorite things about ruby. =).

    - Greg
    Gregory Millam, Apr 3, 2004
    #6
  7. Nicholas Paul Johnson

    Phil Tomson Guest

    In article <>,
    Nicholas Paul Johnson <> wrote:
    >Hello all,
    >
    >As I'm learning Ruby, I've decided to write a few programs in Ruby to get
    >a feel for the language.
    >
    >I've been a C programmer for a long time. As such, I worry that I'm
    >thinking too much like a C programmer, and not like a Ruby programmer...
    >
    >My first attempt has been an emulator for a cs-toy processor called IBCM
    >(itty-bitty computing machine). Its spec (only 5 pages) is available at:
    >http://www.cs.virginia.edu/~cs216/notes/ibcm-poo.pdf
    >
    >I've written it, and it works correctly when compared to my program
    >written in C, but at its core is a large case-when-end statement.
    >This is not `sexy.' I was wondering if there was a better way to do
    >this in Ruby, or if I'm just missing the point.
    >
    >My code is at: http://manjac.ath.cx/nick/ruby-ibcm.rb
    >


    One thing I notice about your code that seems very C-ish is that you use
    only integers as options for your case statements. Ruby's case
    statements are a lot more flexible than C's switch. (Maybe you need to do
    this because you're reading & executing a binary file of IBCM code.) If
    you'd rather work at a higher level of abstraction with assembly code you
    could perhaps do something like:


    case opcode
    when :halt
    #do halt stuff
    when :and
    #do and stuff
    when ...
    end



    Or perhaps you could even define a set of opcode classes that each
    ecapsulate the bahavior of each opcode. Then instead of a case statement
    you could just call a 'execute' (or whatever you want to call it) on each
    statement that you read, so it would look something like:

    class Machine
    include Singleton
    attr_accessor :accum
    def initialize
    @accum = 0
    #define registers, states of the machine here
    end
    end

    class Add
    def initialize(value)
    @value=value
    @machine = Machine.instance
    end
    def execute
    @machine.accum += value #scope of accum is an issue here, of course
    end
    def to_code #so you can convert the mnemonic to a code
    5 #this gives you an assembler for free, but I'm not sure

    end
    end

    def Add(value)
    Add.new(value)
    end

    #...main loop

    File.foreach("IBCM.program"){ |line| #no more case statement
    op = eval(line.strip)
    op.execute #or if you want to convert to machine code: op.to_code
    }


    #contents of IBCM.program:

    Load(0x55)
    Add(2)
    And(0xFF)
    Xor(0x0F)
    #....


    So then your IBCM.program files are actually valid Ruby code.


    ....but then again, if you've got to read in binary data anyway,
    maybe it wouldn't make sense to do it this way.

    Phil
    Phil Tomson, Apr 3, 2004
    #7
  8. Nicholas Paul Johnson wrote:

    >Hello all,
    >
    >As I'm learning Ruby, I've decided to write a few programs in Ruby to get
    >a feel for the language.
    >
    >I've been a C programmer for a long time. As such, I worry that I'm
    >thinking too much like a C programmer, and not like a Ruby programmer...
    >
    >My first attempt has been an emulator for a cs-toy processor called IBCM
    >(itty-bitty computing machine). Its spec (only 5 pages) is available at:
    >http://www.cs.virginia.edu/~cs216/notes/ibcm-poo.pdf
    >
    >I've written it, and it works correctly when compared to my program
    >written in C, but at its core is a large case-when-end statement.
    >This is not `sexy.' I was wondering if there was a better way to do
    >this in Ruby, or if I'm just missing the point.
    >
    >My code is at: http://manjac.ath.cx/nick/ruby-ibcm.rb
    >
    >Thanks all,
    >
    >

    I haven't got any advice over what everyone else has suggested for the
    layout of your program but I have spotted a couple of bugs.

    Firstly the read word instruction doesn't work. It either doesn't take
    any input or if you run the program with the trace option it gives an
    error no such file or directory - -t

    changing the line
    accum = gets.to_i

    to

    accum = $stdin.gets.to_i

    fixes this

    The other problem is the JUMPL instruction jumps even if the acummalator
    isn't less than 0. The problem is in this line

    progcount = off if accum & 0x8000

    since 0 is a true value in Ruby the part accum & 0x8000 is always true.
    You need to change it to

    progcount = off if (accum & ox8000 != 0)

    --
    Mark Sparshatt
    Mark Sparshatt, Apr 3, 2004
    #8
  9. Nicholas Paul Johnson

    Kent S. Guest

    lambda is almost the same thing as Proc.new. Consider this:

    irb(main):001:0> l = lambda{ break }
    => #<Proc:0x00372bf4@(irb):1>
    irb(main):002:0> l.call
    => nil
    irb(main):003:0> p = Proc.new { break }
    => #<Proc:0x00366cdc@(irb):3>
    irb(main):004:0> p.call
    LocalJumpError: break from proc-closure
    from (irb):3:in `call'
    from (irb):4

    Cheers,
    Kent

    On Apr 3, 2004, at 2:43 AM, Gregory Millam wrote:
    >
    > 'proc' is an alias for lambda, but I believe it's to be phased out
    > because of proc/Proc confusin. and lambda is really just "Proc.new"
    >
    > c = Proc.new { |n| 1+n }
    >
    > These blocks, with 'yield,' are among my favorite things about ruby.
    > =).
    >
    > - Greg
    >



    Cheers,
    Kent.
    Kent S., Apr 3, 2004
    #9
  10. Nicholas Paul Johnson

    Ara.T.Howard Guest

    On Sun, 4 Apr 2004, Kent S. wrote:

    > lambda is almost the same thing as Proc.new. Consider this:


    can you elaborate for those of us who are seeing double after a really long
    week?

    -a
    --
    ===============================================================================
    | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
    | PHONE :: 303.497.6469
    | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
    | URL :: http://www.ngdc.noaa.gov/stp/
    | TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
    ===============================================================================
    Ara.T.Howard, Apr 3, 2004
    #10
  11. Nicholas Paul Johnson

    Kent S. Guest

    Sure. Here's what I've got by reading ruby.core:

    1. lambda{} is the same thing as Proc.new{}, except lambda has an arity
    checker plus it rescues 'call' method for LocalJumpError.

    2. proc{} is deprecated in favor of lambda{}.

    3. Proc.new without an associated block is defined like this:

    def method(&block)
    end

    equals

    def method
    block = Proc.new
    end

    and as I know, matz wants to deprecated this Proc.new usage as well.

    Cheers,
    Kent.

    On Apr 3, 2004, at 1:24 PM, Ara.T.Howard wrote:

    > On Sun, 4 Apr 2004, Kent S. wrote:
    >
    >> lambda is almost the same thing as Proc.new. Consider this:

    >
    > can you elaborate for those of us who are seeing double after a really
    > long
    > week?
    Kent S., Apr 3, 2004
    #11
  12. Nicholas Paul Johnson

    Ara.T.Howard Guest

    On Sun, 4 Apr 2004, Kent S. wrote:

    > Sure. Here's what I've got by reading ruby.core:
    >
    > 1. lambda{} is the same thing as Proc.new{}, except lambda has an arity
    > checker plus it rescues 'call' method for LocalJumpError.
    >
    > 2. proc{} is deprecated in favor of lambda{}.
    >
    > 3. Proc.new without an associated block is defined like this:
    >
    > def method(&block)
    > end
    >
    > equals
    >
    > def method
    > block = Proc.new
    > end
    >
    > and as I know, matz wants to deprecated this Proc.new usage as well.
    >
    > Cheers,
    > Kent.


    very cool - good to know.

    -a
    >
    > On Apr 3, 2004, at 1:24 PM, Ara.T.Howard wrote:
    >
    > > On Sun, 4 Apr 2004, Kent S. wrote:
    > >
    > >> lambda is almost the same thing as Proc.new. Consider this:

    > >
    > > can you elaborate for those of us who are seeing double after a really
    > > long
    > > week?

    >
    >
    >
    >


    --
    ===============================================================================
    | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
    | PHONE :: 303.497.6469
    | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
    | URL :: http://www.ngdc.noaa.gov/stp/
    | TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
    ===============================================================================
    Ara.T.Howard, Apr 3, 2004
    #12
  13. >
    >
    > This is a project similar in scope to an NES emulator I've written in C. When doing so, I tried and benchmarked 2 situations:
    >
    > switch (opcode) {
    > case 0x01:
    > case 0x02 ... (etc, for every opcode)
    > }
    >
    > And:
    > typedef void (*operand)(address);
    > operand opcodes[0x100]; (You'd use 0x10)
    > op_0x01(int address) { ... }
    > opcodes[0x01] = op_0x01.
    > Then call using: opcodes[0x01](addr);
    >


    AARRGH! The suspense is killing me!

    Which was faster?!!!


    --
    http://www.it-is-truth.org/
    Asfand Yar Qazi, Apr 5, 2004
    #13
  14. On Tue, Apr 06, 2004 at 02:44:19AM +0900, Asfand Yar Qazi wrote:
    [...]

    Could you please send mail using a valid email user/domainname so that
    I and fellow users don't receive all kinds of errors of choking MTAs/MDAs
    because of the invalidity of using the underscore (_) in domainname
    (im_not_giving_it_here@i_hate_spam.com).
    At LEAST use a dash (-) instead of the underscore.

    Thanks,

    Paul

    --
    Student @ Eindhoven | JID:
    University of Technology, The Netherlands | email:
    >>> Using the Power of Debian GNU/Linux <<< | GnuPG: finger
    Paul van Tilburg, Apr 5, 2004
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rogue Chameleon
    Replies:
    0
    Views:
    538
    Rogue Chameleon
    Oct 22, 2004
  2. striker

    [OT][GEEK] Happy new year.

    striker, Dec 28, 2003, in forum: C Programming
    Replies:
    1
    Views:
    335
    Arthur J. O'Dwyer
    Dec 28, 2003
  3. nobody
    Replies:
    7
    Views:
    1,219
    nobody
    Apr 13, 2004
  4. cplusplus

    GEEK ALERT

    cplusplus, Oct 27, 2007, in forum: C++
    Replies:
    5
    Views:
    417
    James Kanze
    Oct 28, 2007
  5. cplusplus

    GEEK ALERT 2

    cplusplus, Oct 28, 2007, in forum: C++
    Replies:
    1
    Views:
    302
    cplusplus
    Oct 28, 2007
Loading...

Share This Page