[ANN] CplusRuby - Gluing C and Ruby

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

···

----------------------------------------------
CplusRuby - Glue C and Ruby together (OO-like)
----------------------------------------------

COPYRIGHT

   Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de).
   All rights reserved.

LICENSE

   Ruby License.

ABOUT

   With CplusRuby you can define custom C structures from within Ruby and
   wrap them easily in a Ruby class. You can as well define C functions
   that can access this structure easily. CplusRuby generates setter/getter
   methods for every property and wrapper methods for the C functions.

   The purpose is speed! The C functions can access the C-structure,
   which is much faster than accessing instance variables. Also, the C
   functions can call each other directly. This is *much* faster than
   invoking a method in Ruby. As wrappers are generated, the Ruby-side
   can access all C-structures and functions as well.

   I started to write CplusRuby to implement a high-performance pulsed
   neural network simulator. My existing C++ implementation suffered
   from - well - C++ :). This enables me to write the core algorithms
   in C or C++ and do all the other non performance-critical tasks in
   Ruby.

EXAMPLE

   Take a look at the following example. You should also take a look
   at the generated C source file (inspire.c). Note that properties
   are actually members of a C-struct, not instance variables, and as
   such, their access from C is very fast. As calling a method is quite
   slow in Ruby, method defined in C (method_c) can be called directly
   from C, which again is very fast!

     # example.rb
     require 'cplusruby'

     class NeuralEntity < CplusRuby
       property :id
     end

     class Neuron < NeuralEntity
       property :potential, :float
       property :last_spike_time, :float
       property :pre_synapses, :value

       method_c :stimulate, %(float at, float weight), %{
         // this is C code
         selfc->potential += at*weight;
       }

       def initialize
         self.pre_synapses = []
       end
     end

     # generate C file, compile it and load the .so
     CplusRuby.evaluate("inspire.cc", "-O3", "-lstdc++")

     if __FILE__ == $0
       n = Neuron.new
       n.id = "n1"
       n.potential = 1.0
       n.stimulate(1.0, 2.0)
       p n.potential # => 3.0
     end

END

<snip>

First patch!

C:\Documents and Settings\djberge\My Documents\My Downloads\Ruby>diff -
u cplusruby.orig cplusruby.rb
--- cplusruby.orig Fri Sep 21 15:50:38 2007
+++ cplusruby.rb Fri Sep 21 15:49:04 2007
@@ -11,6 +11,10 @@

···

On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote:

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

#
# Implements a simple ordered Hash
#
+require 'rbconfig'
+require 'win32/process' if RUBY_PLATFORM.match('mswin')
+include Config
+
class OHash < Hash
   def =(k, v)
     @order ||=
@@ -146,20 +150,28 @@
     dir = File.dirname(file)
     mod, ext = base.split(".")

+ make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
+
     File.open(file, 'w+') {|f| f << self.generate_code(mod) }
     Dir.chdir(dir) do
- system("make clean")
+ system("#{make} clean")
+
       pid = fork do
         require 'mkmf'
         $CFLAGS = cflags
         $LIBS << (" " + libs)
         create_makefile(mod)
- exec "make"
+ exec "#{make}"
       end
       _, status = Process.waitpid2(pid)
- raise if status.exitstatus != 0
+
+ if RUBY_PLATFORM.match('mswin')
+ raise if status != 0
+ else
+ raise if status.exitstatus != 0
+ end
     end
- require "#{dir}/#{mod}.so"
+ require "#{dir}/#{mod}." + CONFIG['DLEXT']
   end

   def self.generate_code_for_class

Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
that don't generate .so files (OS X, HP-UX).

Regards,

Dan

Michael Neumann wrote:

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

----------------------------------------------
CplusRuby - Glue C and Ruby together (OO-like)
----------------------------------------------

It's been done, but I'm glad to see it done again and probably with new ideas :slight_smile:

For comparison:

   require 'cgen/cshadow' # from cgen on RAA

   class NeuralEntity
     include CShadow
     attr_accessor :id
   end

   class Neuron < NeuralEntity
     shadow_attr_accessor :potential => "double potential"
     shadow_attr_accessor :last_spike_time => "double last_spike_time"
     shadow_attr_accessor :pre_synapses => Object

     define_c_method :stimulate do
       arguments :at, :weight
       body %{
         shadow->potential += NUM2DBL(at)*NUM2DBL(weight);
       }
     end

     def initialize
       self.pre_synapses =
     end
   end

   NeuralEntity.commit # generate and load the shared lib

   if __FILE__ == $0
     n = Neuron.new
     n.id = "n1"
     n.potential = 1.0
     n.stimulate(1.0, 2.0)
     p n.potential # => 3.0
   end

Cgen is middle aged, as ruby libraries go (written mostly in 2001), and it probably isn't up to community standards in a number of ways. Still, I've used it intensively in numerical and hybrid simulation since then. It's the foundation for redshift, which is a DSL for simulation of hybrid automata (networked state machines with continuous as well as discrete dynamics).

Cgen/cshadow handles a number of issues for you:

- creating accessors (r, w, rw)
- type checking and conversion in the write accessor
- mark and free functions
- attr initialization
- persistence via marshal and yaml (or an attr may be specified non-persistent)
- extensible attribute classes for defining new attr types, other than the basic numeric, string, and Ruby object types
- inheritance (a subclass of a shadow class inherits the parent's shadow attrs in its own C struct; struct may be safely cast to parent type)
- tools for managing how code is distributed among files (very important with a large project, or else recompilation time gets painful).
- tools for managing declarations and preprocessor includes
- DSL for rb_scan_args()

This is pretty well documented, though it is in the old rd format, rather than rdoc.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

One comment on inheritance in cplusruby:

   def self.inherited(klass)
     # inherit properties and c_methods
     self.properties.each {|k,v| klass.properties[k] = v}
     CplusRuby.registered_classes << klass
   end

Re-opening a parent class after a child class has been defined and adding more properties will not propagate them to the child. And you can't simply add such properties to the end of the parent and child struct definitions, since that will make them incompatible (in the sense of casting).

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Why not use RubyInline?

You'll get more than twice the utility and drop a bunch of code.

···

On Sep 21, 2007, at 12:01, Michael Neumann wrote:

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

[...]
      system("#{make} clean")

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars

:char_p => {
  :default => '""',
  :ctype => 'char* %s',
  :ruby2c => 'StringValuePtr(%s)',
  :c2ruby => 'rb_str_new2(%s)'}

I think you'll want to store either a copy of the string or a reference
to the string object (which would need to be marked). If you don't, the
string could be destroyed before the containing struct, which would
leave you with a dangling pointer.

Paul

Quoth Daniel Berger:

> Hi all,
>
> I am proud to announce my latest project called CplusRuby.
> Below I pasted it's README for further explanation.
> Alternatively read the following blog article:
>
> http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

<snip>

First patch!

C:\Documents and Settings\djberge\My Documents\My Downloads\Ruby>diff -
u cplusruby.orig cplusruby.rb
--- cplusruby.orig Fri Sep 21 15:50:38 2007
+++ cplusruby.rb Fri Sep 21 15:49:04 2007
@@ -11,6 +11,10 @@
#
# Implements a simple ordered Hash
#
+require 'rbconfig'
+require 'win32/process' if RUBY_PLATFORM.match('mswin')
+include Config
+
class OHash < Hash
   def =(k, v)
     @order ||=
@@ -146,20 +150,28 @@
     dir = File.dirname(file)
     mod, ext = base.split(".")

+ make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
+
     File.open(file, 'w+') {|f| f << self.generate_code(mod) }
     Dir.chdir(dir) do
- system("make clean")
+ system("#{make} clean")
+
       pid = fork do
         require 'mkmf'
         $CFLAGS = cflags
         $LIBS << (" " + libs)
         create_makefile(mod)
- exec "make"
+ exec "#{make}"
       end
       _, status = Process.waitpid2(pid)
- raise if status.exitstatus != 0
+
+ if RUBY_PLATFORM.match('mswin')
+ raise if status != 0
+ else
+ raise if status.exitstatus != 0
+ end
     end
- require "#{dir}/#{mod}.so"
+ require "#{dir}/#{mod}." + CONFIG['DLEXT']
   end

   def self.generate_code_for_class

Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
that don't generate .so files (OS X, HP-UX).

Regards,

Dan

Does the C->ruby mapping map between char * and Strings?

Thanks,

···

On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote:

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Daniel Berger schrieb:

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

<snip>

First patch!

Thanks! Applied!

I didn't know that adding Windows support is that easy. Cool!

BTW, I am using Mercurial as repository, so it should be easy for everyone to keep track of changes. To get the repository:

   hg clone static-http://ntecs.de/hg-projects/cplusruby

Regards,

   Michael

···

On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote:

Hi,

At Sat, 22 Sep 2007 06:54:13 +0900,
Daniel Berger wrote in [ruby-talk:270261]:

+ if RUBY_PLATFORM.match('mswin')
+ raise if status != 0
+ else
+ raise if status.exitstatus != 0
+ end

I'm curious why win32/process doesn't return Process::Status.

···

--
Nobu Nakada

Joel VanderWerf schrieb:

Michael Neumann wrote:

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

----------------------------------------------
CplusRuby - Glue C and Ruby together (OO-like)
----------------------------------------------

It's been done, but I'm glad to see it done again and probably with new ideas :slight_smile:

Wow, cool! I knew about cgen, but then didn't knew that it's that easy to use.

In the example you give I only see one minor difference. In CplusRuby, method :stimulate can be called directly from the C-side, without NUM2DBL conversions of Ruby-types. That's very important for my
usage scenario.
But I think you can do the same with cgen.

Regards,

   Michael

Daniel Berger wrote:

- require "#{dir}/#{mod}.so"
+ require "#{dir}/#{mod}." + CONFIG['DLEXT']
   end

   def self.generate_code_for_class

Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
that don't generate .so files (OS X, HP-UX).

Why not just

> + require "#{dir}/#{mod}"

which should work if there are no stray .rb files in the dir?

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Eric Hodel schrieb:

···

On Sep 21, 2007, at 12:01, Michael Neumann wrote:

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

[...]
      system("#{make} clean")

Why not use RubyInline?

You'll get more than twice the utility and drop a bunch of code.

Drop less than 20 lines of code? It really takes longer to get into RubyInline than to write those 20 lines :slight_smile:

Regards,

   Michael

Quoth Paul Brannan:

:char_p => {
  :default => '""',
  :ctype => 'char* %s',
  :ruby2c => 'StringValuePtr(%s)',
  :c2ruby => 'rb_str_new2(%s)'}

I think you'll want to store either a copy of the string or a reference
to the string object (which would need to be marked). If you don't, the
string could be destroyed before the containing struct, which would
leave you with a dangling pointer.

Paul

Yes, I believe that's the problem I ran into.

···

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Quoth Konrad Meyer:

Quoth Daniel Berger:
>
> > Hi all,
> >
> > I am proud to announce my latest project called CplusRuby.
> > Below I pasted it's README for further explanation.
> > Alternatively read the following blog article:
> >
> > http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby
>
> <snip>
>
> First patch!
>
> C:\Documents and Settings\djberge\My Documents\My Downloads\Ruby>diff -
> u cplusruby.orig cplusruby.rb
> --- cplusruby.orig Fri Sep 21 15:50:38 2007
> +++ cplusruby.rb Fri Sep 21 15:49:04 2007
> @@ -11,6 +11,10 @@
> #
> # Implements a simple ordered Hash
> #
> +require 'rbconfig'
> +require 'win32/process' if RUBY_PLATFORM.match('mswin')
> +include Config
> +
> class OHash < Hash
> def =(k, v)
> @order ||=
> @@ -146,20 +150,28 @@
> dir = File.dirname(file)
> mod, ext = base.split(".")
>
> + make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
> +
> File.open(file, 'w+') {|f| f << self.generate_code(mod) }
> Dir.chdir(dir) do
> - system("make clean")
> + system("#{make} clean")
> +
> pid = fork do
> require 'mkmf'
> $CFLAGS = cflags
> $LIBS << (" " + libs)
> create_makefile(mod)
> - exec "make"
> + exec "#{make}"
> end
> _, status = Process.waitpid2(pid)
> - raise if status.exitstatus != 0
> +
> + if RUBY_PLATFORM.match('mswin')
> + raise if status != 0
> + else
> + raise if status.exitstatus != 0
> + end
> end
> - require "#{dir}/#{mod}.so"
> + require "#{dir}/#{mod}." + CONFIG['DLEXT']
> end
>
> def self.generate_code_for_class
>
> Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
> that don't generate .so files (OS X, HP-UX).
>
> Regards,
>
> Dan

Does the C->ruby mapping map between char * and Strings?

Thanks,
--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Okay, so I have added the following to DEFAULT_OPTIONS:

    :int => {
      :default => '0',
      :ctype => 'int %s',
      :ruby2c => '(int)NUM2INT(%s)',
      :c2ruby => 'INT2NUM(%s)'},

    :char_p => {
      :default => '""',
      :ctype => 'char *%s',
      :ruby2c => 'StringValuePtr(%s)',
      :c2ruby => 'rb_str_new2(%s)'}

My code is like this:

#---------------------start

require 'cplusruby'

class BankAccount < CplusRuby
  property :balance, :int
  property :name, :char_p

  method_c :withdraw, %{int dollars}, %{
    if (dollars <= selfc->balance){
      selfc->balance -= dollars;
      return true;
    }
  }

  def initialize
  end
end

CplusRuby.evaluate("foo.c", "-Os", "")

n = BankAccount.new
puts n.balance
puts n.name

#---------------------end

When I run it with ruby I get a whole bunch of errors stemming from
the fact that it generates C code that uses a type called
"BankAccount" without defining it anywhere (struct BankAccount is
defined though).

Ideas, suggestions, questions?

Thanks,

···

> On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote:

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Quoth Konrad Meyer:

Quoth Daniel Berger:
>
> > Hi all,
> >
> > I am proud to announce my latest project called CplusRuby.
> > Below I pasted it's README for further explanation.
> > Alternatively read the following blog article:
> >
> > http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby
>
> <snip>
>
> First patch!
>
> C:\Documents and Settings\djberge\My Documents\My Downloads\Ruby>diff -
> u cplusruby.orig cplusruby.rb
> --- cplusruby.orig Fri Sep 21 15:50:38 2007
> +++ cplusruby.rb Fri Sep 21 15:49:04 2007
> @@ -11,6 +11,10 @@
> #
> # Implements a simple ordered Hash
> #
> +require 'rbconfig'
> +require 'win32/process' if RUBY_PLATFORM.match('mswin')
> +include Config
> +
> class OHash < Hash
> def =(k, v)
> @order ||=
> @@ -146,20 +150,28 @@
> dir = File.dirname(file)
> mod, ext = base.split(".")
>
> + make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
> +
> File.open(file, 'w+') {|f| f << self.generate_code(mod) }
> Dir.chdir(dir) do
> - system("make clean")
> + system("#{make} clean")
> +
> pid = fork do
> require 'mkmf'
> $CFLAGS = cflags
> $LIBS << (" " + libs)
> create_makefile(mod)
> - exec "make"
> + exec "#{make}"
> end
> _, status = Process.waitpid2(pid)
> - raise if status.exitstatus != 0
> +
> + if RUBY_PLATFORM.match('mswin')
> + raise if status != 0
> + else
> + raise if status.exitstatus != 0
> + end
> end
> - require "#{dir}/#{mod}.so"
> + require "#{dir}/#{mod}." + CONFIG['DLEXT']
> end
>
> def self.generate_code_for_class
>
> Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
> that don't generate .so files (OS X, HP-UX).
>
> Regards,
>
> Dan

Does the C->ruby mapping map between char * and Strings?

Thanks,
--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Also, is there a way to define C functions from ruby that return a C type?

···

> On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote:

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Nobuyoshi Nakada wrote:

Hi,

At Sat, 22 Sep 2007 06:54:13 +0900,
Daniel Berger wrote in [ruby-talk:270261]:

+ if RUBY_PLATFORM.match('mswin')
+ raise if status != 0
+ else
+ raise if status.exitstatus != 0
+ end

I'm curious why win32/process doesn't return Process::Status.

We had to reimplement waitpid and waitpid2 because of our custom fork implementation. But, we weren't sure how to set $? manually to a Process::Status object in pure Ruby. Do you have any suggestions?

Thanks,

Dan

Michael Neumann wrote:

In the example you give I only see one minor difference. In CplusRuby, method :stimulate can be called directly from the C-side, without NUM2DBL conversions of Ruby-types. That's very important for my
usage scenario.
But I think you can do the same with cgen.

Actually, I don't think cgen has that feature.... one of the things I'll have to er, borrow, from cplusruby. Currently the only way to do this is to define a separate C function that the method calls.

Reading the cplusruby .c output, it looks like there is an outer function (Neuron_call__stimulate) that accepts ruby value arguments, and then converts them and calls an inner function (Neuron__stimulate), which expects C-typed arguments. You could do this in cgen by using define_c_method to define the outer function and define_c_function to define the inner function.

I guess I was used to performing the conversion manually, so I never added that feature as a convenience. I can see that it would be more of a necessity than a convenience if the function needed to be called from C as well as ruby.

The selfc->stimulate function pointer is another difference, and necessary for the same reason, I guess. In a cshadow struct, this struct member doesn't exist, but there is reference ("VALUE self;") back to the original object, on which you can call methods (with the additional friction of type conversions, if the caller is native C code).

The fact that you have pointers to functions that accept C-typed args makes access from C easy and efficient, but it also uses a lot of space in the struct with a pointer to each function that implements a method. What about having a unique struct for each class that keeps these pointers, and then the struct only needs a pointer to this "singleton"?

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

Thanks for the announce. I will keep an eye on your project when it
comes to speed with Rubyk. By the way, did anyone play with
RubyInline+Ruby2c like in the example below ?
require 'inline'
class MyTest

  def factorial(n)
    f = 1
    n.downto(2) { |x| f *= x }
    f
  end

  inline(:Ruby) do |builder|
    builder.optimize :factorial
  end
end

Gaspard

Hi,

At Sun, 23 Sep 2007 06:50:05 +0900,
Joel VanderWerf wrote in [ruby-talk:270374]:

> - require "#{dir}/#{mod}.so"
> + require "#{dir}/#{mod}." + CONFIG['DLEXT']
> end
>
> def self.generate_code_for_class
>
> Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
> that don't generate .so files (OS X, HP-UX).

Why not just

> + require "#{dir}/#{mod}"

which should work if there are no stray .rb files in the dir?

Actually, CONFIG['DLEXT'] is unnecessary at all and that code
works fine with ".so" on every platforms, since the extension
".so" will be substituted with DLEXT internally.

···

--
Nobu Nakada

Konrad Meyer schrieb:

Quoth Konrad Meyer:

Quoth Daniel Berger:

Hi all,

I am proud to announce my latest project called CplusRuby.
Below I pasted it's README for further explanation.
Alternatively read the following blog article:

http://www.ntecs.de/blog/articles/2007/09/21/cplusruby-gluing-c-and-ruby

<snip>

First patch!

C:\Documents and Settings\djberge\My Documents\My Downloads\Ruby>diff -
u cplusruby.orig cplusruby.rb
--- cplusruby.orig Fri Sep 21 15:50:38 2007
+++ cplusruby.rb Fri Sep 21 15:49:04 2007
@@ -11,6 +11,10 @@
#
# Implements a simple ordered Hash
#
+require 'rbconfig'
+require 'win32/process' if RUBY_PLATFORM.match('mswin')
+include Config
+
class OHash < Hash
   def =(k, v)
     @order ||=
@@ -146,20 +150,28 @@
     dir = File.dirname(file)
     mod, ext = base.split(".")

+ make = RUBY_PLATFORM.match('mswin') ? 'nmake' : 'make'
+
     File.open(file, 'w+') {|f| f << self.generate_code(mod) }
     Dir.chdir(dir) do
- system("make clean")
+ system("#{make} clean")
+
       pid = fork do
         require 'mkmf'
         $CFLAGS = cflags
         $LIBS << (" " + libs)
         create_makefile(mod)
- exec "make"
+ exec "#{make}"
       end
       _, status = Process.waitpid2(pid)
- raise if status.exitstatus != 0
+
+ if RUBY_PLATFORM.match('mswin')
+ raise if status != 0
+ else
+ raise if status.exitstatus != 0
+ end
     end
- require "#{dir}/#{mod}.so"
+ require "#{dir}/#{mod}." + CONFIG['DLEXT']
   end

   def self.generate_code_for_class

Mostly fixes MS Windows issues, but the DLEXT bit also fixes platforms
that don't generate .so files (OS X, HP-UX).

Regards,

Dan

Does the C->ruby mapping map between char * and Strings?

Thanks,
--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertillnoon.com/

Okay, so I have added the following to DEFAULT_OPTIONS:

    :int => {
      :default => '0',
      :ctype => 'int %s',
      :ruby2c => '(int)NUM2INT(%s)',
      :c2ruby => 'INT2NUM(%s)'},

    :char_p => {
      :default => '""',
      :ctype => 'char *%s',
      :ruby2c => 'StringValuePtr(%s)',
      :c2ruby => 'rb_str_new2(%s)'}

My code is like this:

#---------------------start

require 'cplusruby'

class BankAccount < CplusRuby
  property :balance, :int
  property :name, :char_p

  method_c :withdraw, %{int dollars}, %{
    if (dollars <= selfc->balance){
      selfc->balance -= dollars;
      return true;

I think you shouldn't return "true" here. At least it's
not indended, as the withdraw function is "void".

    }
  }

  def initialize
  end
end

CplusRuby.evaluate("foo.c", "-Os", "")

n = BankAccount.new
puts n.balance
puts n.name

#---------------------end

When I run it with ruby I get a whole bunch of errors stemming from
the fact that it generates C code that uses a type called
"BankAccount" without defining it anywhere (struct BankAccount is
defined though).

I think C does not yet work. Try C++ :slight_smile:

CplusRuby.evaluate("foo.cc" ...)

But it should be easy to fix, by adding a "typedef struct", and
"VALUE(*)()" instead of "VALUE (*)(...)".

Ah, and returns values are not yet implemented. Nevertheless you can
assign to a property and use it as a return value.

Thanks,

   Michael

···

On Sep 21, 1:01 pm, Michael Neumann <mneum...@ntecs.de> wrote: