Professional Web Applications Themes

C++ from Ruby ARRRGGHH!! - Ruby

Yes, I know there's a wrapper available already that can wrap C++ exceptions in Ruby, but I want to do it myself as a learning exercise. Anyway, could you look at the following test code that reveals the problem? I just don't know what to do! Are C++ exceptions in GCC incompatible with Ruby exceptions? I think that's the problem, isn't it... (I have put a link to an archive with these files, plus the library binary, here: http://users.wmin.ac.uk/~w9921783/ruby-test.tar.gz) =====file Makefile Test.so: ruby-test.cc g++ -shared -o $ -I`ruby -rrbconfig \ -e 'puts Config::CONFIG["archdir"]'` $< =====file t.rb #!/usr/local/bin/ruby -w require 'Test' ...

  1. #1

    Default C++ from Ruby ARRRGGHH!!

    Yes, I know there's a wrapper available already that can wrap C++
    exceptions in Ruby, but I want to do it myself as a learning exercise.

    Anyway, could you look at the following test code that reveals the
    problem? I just don't know what to do! Are C++ exceptions in GCC
    incompatible with Ruby exceptions? I think that's the problem, isn't it...

    (I have put a link to an archive with these files, plus the library
    binary, here: http://users.wmin.ac.uk/~w9921783/ruby-test.tar.gz)

    =====file Makefile
    Test.so: ruby-test.cc
    g++ -shared -o $ -I`ruby -rrbconfig \
    -e 'puts Config::CONFIG["archdir"]'` $<

    =====file t.rb
    #!/usr/local/bin/ruby -w

    require 'Test'

    include Mod

    Test.init
    (1..20).each() do
    begin
    Test.init
    rescue CPP_Error => e
    puts("C++ exception '#{e.cppclass}' occured, message = \"#{e.message}\"");
    rescue Exception => e
    puts("Exception #{e.class.name} occured: #{e.message}");
    end
    end

    Test.deinit

    =====file ruby-test.cc

    #include "ruby.h"
    #include <stdexcept>
    #include <string>
    #include <typeinfo>

    namespace
    {

    struct Test
    {
    static bool init_;

    static void
    init()
    {
    if(!init_)
    init_ = true;
    else
    throw std::runtime_error("DDStuff");
    }

    static bool
    is_init() {return init_;}

    static void
    deinit() {init_ = false;}
    };

    bool Test::init_ = false;

    VALUE cTest;

    /// Module
    VALUE mMod;

    /// C++ exception
    VALUE eCPP_Error;

    /// Define a class (as rb_define_class) under mMod
    inline VALUE defclass(const char *name, VALUE super)
    {
    return rb_define_class_under(mMod, name, super);
    }

    /// Convert boolean to Qtrue/Qfalse
    inline VALUE convbool(bool arg) {if(arg)return Qtrue; else return Qfalse;}

    /// Takes an exception 'e', gets its name and 'what' message, and uses
    /// it to throw a Ruby exception
    void
    raise_ruby(std::exception& e)
    {
    std::string classname = typeid(e).name();

    /*
    COMMENT: This gives the error message show in Init_Test

    */
    // VALUE excep = rb_funcall(eCPP_Error, rb_intern("new"), 1,
    // rb_str_new2(classname.c_str()));
    // rb_raise(excep, e.what());



    // COMMENT: WITH THE FOLLOWING instead of the above, when Test.init
    // has been called a certain number of times, a segfault occurs

    std::string eval_string = "raise CPP_Error.new('" + classname
    + "'), '" + e.what() + "'";
    rb_eval_string(eval_string.c_str());
    }

    /// define CHECK_CPP Call given C++ code, and check it for
    /// exceptions, throwing if necessary
    #define CHECK_CPP(code) try {code;} catch(std::exception& e)
    {raise_ruby(e);}

    // Test
    VALUE
    Test__init(VALUE self)
    {
    CHECK_CPP(Test::init());
    return self;
    }

    VALUE
    Test__is_init(VALUE self)
    {
    return convbool(Test::is_init());
    }

    VALUE
    Test__deinit(VALUE self)
    {
    Test::deinit();
    return self;
    }

    // Call with 'cppclass'
    VALUE
    CPP_Error__initialize(int argc, VALUE* argv, VALUE self)
    {
    VALUE argcppclass;
    VALUE argmessage;

    if(rb_scan_args(argc, argv, "12", &argcppclass, &argmessage) == 1)
    argmessage = rb_str_new2("");
    StringValue(argcppclass);
    rb_call_super(1, &argmessage);
    rb_iv_set(self, "cppclass", argcppclass);

    return self;
    }

    VALUE
    test(...)
    {
    // VALUE retval = INT2FIX(0);
    // StringValue(retval);
    // return retval;

    VALUE tmp = rb_funcall(eCPP_Error, rb_intern("new"),
    1, rb_str_new2("AnException"));
    return tmp;

    // rb_funcall(rb_mKernel, rb_intern("p"), 1,
    // rb_funcall(eCPP_Error, rb_intern("inspect"), 0));
    // return rb_funcall(eCPP_Error, rb_intern("inspect"), 0);
    // return eCPP_Error;
    }

    } // namespace

    typedef VALUE(*rbfunk)(...);

    extern "C" void Init_Test()
    {
    // module Mod
    mMod = rb_define_module("Mod");

    rb_define_global_function("testsr", test, 0);

    /*
    COMMENT: Using raise-ruby.c block 1, regardless of which of the
    following styles I try, I get the following:

    ../t.rb:10:in `init': undefined method `new' for
    Mod::CPP_Error:Mod::CPP_Error (NoMethodError)
    from ./t.rb:10
    from ./t.rb:8:in `each'
    from ./t.rb:8

    However, see the 'raise_ruby' func above...
    */

    // STYLE1
    eCPP_Error = defclass("CPP_Error", rb_eRuntimeError);
    rb_define_method(eCPP_Error, "initialize",
    (rbfunk)CPP_Error__initialize, -1);
    rb_eval_string("class Mod::CPP_Error; attr_reader(:cppclass);end");
    // END STYLE1

    // STYLE2
    // rb_eval_string("module Mod\n"
    // " class CPP_Error < RuntimeError\n"
    // " def initialize(cppclass, message = '')\n"
    // " super(message)\n"
    // " cppclass = cppclass\n"
    // " end\n"
    // " attr_reader(:cppclass)\n"
    // " end\n"
    // "end\n");
    // eCPP_Error = rb_eval_string("Mod::CPP_Error");
    // STYLE2

    cTest = defclass("Test", rb_cObject);
    rb_define_singleton_method(cTest, "init",
    (rbfunk)Test__init, 0);
    rb_define_singleton_method(cTest, "is_init?",
    (rbfunk)Test__is_init, 0);
    rb_define_singleton_method(cTest, "deinit",
    (rbfunk)Test__deinit, 0);
    }





    --
    http://www.it-is-truth.org/

    Asfand Guest

  2. #2

    Default Re: C++ from Ruby ARRRGGHH!!

    Hi,

    At Sun, 18 Jan 2004 16:20:01 +0900,
    Asfand Yar Qazi wrote: 

    Yes, of course, incompatible. They aren't concerned with at
    all. You have to protect or wrap each exceptions at every
    boundaries.

    --
    Nobu Nakada

    nobu.nokada@softhome.net Guest

  3. #3

    Default Re: C++ from Ruby ARRRGGHH!!

    net wrote: 
    >
    >
    > Yes, of course, incompatible. They aren't concerned with at
    > all. You have to protect or wrap each exceptions at every
    > boundaries.
    >[/ref]

    As you can see from the code...

    #define CHECK_CPP(code) try {code;} \
    catch(std::exception& e) {raise_ruby(e);}

    i.e. catch a C++ exception, wrap its contents in a Ruby exception,
    dispatch that Ruby exception. But that corrupts the program stack I
    think, resulting in really funny and annoying errors (as doented in
    the OP), and eventually resulting in a coredump. Its all due to the
    setjmp/longjmp used by Ruby exceptions and GCC's advanced
    exception-handling mechanism, which are incompatible.

    I wait for the day when a scripting language will be written in C++, and
    be fully compatible will C++ features (perhaps even with templates.)
    But still, I'll just redo my C++ code in a Ruby-esque way, i.e. throwing
    Ruby exceptions instead of C++ exceptions, so no problems.

    --
    http://www.it-is-truth.org/

    Asfand Guest

  4. #4

    Default Re: C++ from Ruby ARRRGGHH!!

    Hi,

    At Sun, 18 Jan 2004 16:20:01 +0900,
    Asfand Yar Qazi wrote: 

    This must be "11", numbers of mandatory arguments and optional
    arguments, second is not the total.

    --
    Nobu Nakada

    nobu.nokada@softhome.net Guest

  5. #5

    Default Re: C++ from Ruby ARRRGGHH!!

    net wrote: 
    >
    >
    > This must be "11", numbers of mandatory arguments and optional
    > arguments, second is not the total.
    >[/ref]

    Ah... one day, someone should do a rewrite on README.EXT :-)

    That said, I used another method and it didn't do anything differently,
    so this can't have been the problem.


    --
    http://www.it-is-truth.org/

    Asfand Guest

Similar Threads

  1. Ruby/Ruby on Rails Syntax Highlight/Code completion
    By Cannikinn in forum Macromedia Exchange Dreamweaver Extensions
    Replies: 1
    Last Post: September 22nd, 01:05 AM
  2. Replies: 0
    Last Post: November 1st, 05:21 PM
  3. Replies: 1
    Last Post: October 29th, 07:52 PM
  4. ruby-talk: 80813 (Rite/Ruby2.0 & Ruby vs OCaml)
    By Steven Lumos in forum Ruby
    Replies: 0
    Last Post: October 9th, 10:21 PM
  5. [ANN] ruby-freedb, ruby-serialport, ruby-mp3info moved to Rubyforge
    By guillaume.pierronnet@ratp.fr in forum Ruby
    Replies: 0
    Last Post: August 31st, 11:57 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139