Advocacy: Ruby on/with .net

M

Mauricio Fernández

Rodrigo B. de Oliveira said:
I feel exactly the same way. When do we start coding? :)
[...]

There is a mailing list
http://sourceforge.net/mailarchive/forum.php?forum_id=34312
for discussing all things to do with Ruby and .NET.

I have code right now which allows you to do things like
require 'dotnet'

DotNet.System.Console.WriteLine("Hello DotNet World!")

foo = DotNet.System.Collections.Hashtable.new
foo['one'] = 1
puts(foo['one']) # -> 1

It also allows C# to call Ruby code.

This is *very* similar in spirit to what I'm doing w/ Java (through
JNI). If I got it right (I did a quick inspection of your code), you're
linking to the C# runtime, so you have both parts running on the same
process at a time (as opposed to communicating through sockets for
instance).

BTW, you have achieved about the same (if not more) in < 2Klocs than me
in 8Kloc (although some 4Kloc are auto-generated).

Did you solve the problem w/ threads (does it happen at all w/
C# ?)

In my case, Java threads are spawned as "real" (native) threads, so if
any of them tries to call Ruby code the thing will bomb (Ruby not being
thread safe).

A few more questions:
* are you doing proper method dispatching on method overload?
This can be tricky if you perform automatic Ruby -> C#/Java type
conversions as there might be several matching methods
* do you have metaclasses for static methods or such? Do you think it's
sensible to provide them? (I did that in rjni)

I'll take another look at your code when I have some time but as I know
nothing about .net I don't know if I will understand it.

And last: is it just me, or C# is insanely easier to interface with than Java?
There's several things in your code that take many more lines when using JNI...

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

<SomeLamer> what's the difference between chattr and chmod?
<SomeGuru> SomeLamer: man chattr > 1; man chmod > 2; diff -u 1 2 | less
-- Seen on #linux on irc
 
T

Tim Sutherland

Mauricio said:
Rodrigo B. de Oliveira said:
I feel exactly the same way. When do we start coding? :)
[...]

There is a mailing list
http://sourceforge.net/mailarchive/forum.php?forum_id=34312
for discussing all things to do with Ruby and .NET.

I have code right now which allows you to do things like
require 'dotnet'

DotNet.System.Console.WriteLine("Hello DotNet World!")

foo = DotNet.System.Collections.Hashtable.new
foo['one'] = 1
puts(foo['one']) # -> 1

It also allows C# to call Ruby code.

This is *very* similar in spirit to what I'm doing w/ Java (through
JNI). If I got it right (I did a quick inspection of your code), you're
linking to the C# runtime, so you have both parts running on the same
process at a time (as opposed to communicating through sockets for
instance).

Yes, that is how I am doing it. NB: I'm planning to make the first
'real' release of my rubydotnetproxy library by the upcoming Monday.
BTW, you have achieved about the same (if not more) in < 2Klocs than me
in 8Kloc (although some 4Kloc are auto-generated).

Did you solve the problem w/ threads (does it happen at all w/
C# ?)

In my case, Java threads are spawned as "real" (native) threads, so if
any of them tries to call Ruby code the thing will bomb (Ruby not being
thread safe).

No, I did not solve the thread problem. In addition to the problem with
dotnet threads, if you are using Ruby threads then a call to a dotnet
object can block, preventing other Ruby threads from running.
A few more questions:
* are you doing proper method dispatching on method overload?
This can be tricky if you perform automatic Ruby -> C#/Java type
conversions as there might be several matching methods

I only do a few automatic type conversions, e.g. strings. What problems
are you thinking of?

The dotnet method I am using is Type#InvokeMember which claims to choose
the best method.
* do you have metaclasses for static methods or such? Do you think it's
sensible to provide them? (I did that in rjni)

I'm not sure what you mean.

You can do
klass = DotNet.SomeNamespace.SomeClass
klass.SomeStaticMethod("Hello")

inst = klass.new(1, 2, 3)
inst.SomeStaticMethod("World")
inst.SomeInstanceMethod(42)
I'll take another look at your code when I have some time but as I know
nothing about .net I don't know if I will understand it.

And last: is it just me, or C# is insanely easier to interface with than Java?
There's several things in your code that take many more lines when using JNI...

I've never used JNI, so I can't say.

I think it would have been easier for me if I'd been willing to use
Microsoft's "Managed C++" language. This is a language based off C++
which can easily call dotnet code, C code and be called by C code.

Unfortunately Mono is not planning to implement this language so I wrote
half of my library in C# instead. It is easy to call C code from C#,
however it is not so easy to call C# code from C. My solution is to have
a small (~10 lines) library written in Managed C++ which causes the C#
library to call a C function in my library, passing in a bunch of
function pointers.

The C code can then call these functions to access dotnet features.

Ben Schroeder and John R. Pierce have written a similar library which
uses sockets. It implements an interesting feature (not yet available in
my library) which is to turn Ruby blocks into C# Delegates (these are
like function pointers.)

Ben offers the following example:

dotNet.loadLibrary('System.Windows.Forms')

button = dotNet.Button.new

button.click.add do |sender, args|
puts "Button clicked!"
end

button.performClick # -> prints <<Button clicked!>>
 
M

Mauricio Fernández

No, I did not solve the thread problem. In addition to the problem with
dotnet threads, if you are using Ruby threads then a call to a dotnet
object can block, preventing other Ruby threads from running.

Yes, there's no easy way to work around the latter until we get Rite.
I only do a few automatic type conversions, e.g. strings. What problems
are you thinking of?

The dotnet method I am using is Type#InvokeMember which claims to choose
the best method.

I think it's easier to call C# code from C than using JNI to run Java
code... In my case, it's up to me to find the correct method, with the
appropriate signature, before dispatching. This can be quite slow as I
have to use reflection at run time quite heavily: get the list of
methods of an object, get the return type and parameter types of each
method, check passed arguments and perform type conversions (just String ->
java.lang.String, Object -> boolean and Numeric -> one of char, byte,
short, int, long, float, double)
I'm not sure what you mean.

You can do
klass = DotNet.SomeNamespace.SomeClass
klass.SomeStaticMethod("Hello")

inst = klass.new(1, 2, 3)
inst.SomeStaticMethod("World")
inst.SomeInstanceMethod(42)

When using JNI, I have to implement it myself if I intent to call
static methods (which are like singleton methods in Ruby) on some class,
creating a proxy object to delegate the calls, etc.
Ben Schroeder and John R. Pierce have written a similar library which
uses sockets. It implements an interesting feature (not yet available in
my library) which is to turn Ruby blocks into C# Delegates (these are
like function pointers.)

Ben offers the following example:

dotNet.loadLibrary('System.Windows.Forms')

button = dotNet.Button.new

button.click.add do |sender, args|
puts "Button clicked!"
end

button.performClick # -> prints <<Button clicked!>>

I can do that in my code (implement Java interfaces in Ruby and pass
them to Java code) but this won't work with GUIs since I face again the
threading issue. That's why I was thinking of using sockets, too, but
Robert Klemme had an interesting idea I might be able to implement.

What speed are you getting with rubydotnet? I suspect it will be much
faster than RJNI since C#'s C interface seems to be much more sensible
than JNI.

In my case, when using the low-level JNI methods from Ruby I get around
200000 method calls/s on a K7 1.3GHz.
When using the "automagic reflection" (that is the higher-level part
similar to rubydotnet), I get some 20000 method calls/s. But I can
easily make it much faster since
* it's using the wrapped JNI calls from Ruby instead of the C JNI API
directly
* it's implemented in Ruby at the moment (this means type checking,
conversions, etc) using the JNI binding

Once I fix the Ruby code I can reimplement everything in C and I expect
to approach 500000 method calls/s or so.

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

The state of some commercial Un*x is more unsecure than any Linux box
without a root password...
-- Bernd Eckenfels
 
T

Tim Sutherland

Tim Sutherland wrote: said:
Yes, that is how I am doing it. NB: I'm planning to make the first
'real' release of my rubydotnetproxy library by the upcoming Monday.
[...]

Monday has passed and I haven't released...I've been battling one bug
for a number of days - when I call one C# method, bad stuff appears to be
happening with the stack pointer. Hopefully it's just a bug somewhere in my C
code which can easily be fixed once found.
 
F

Fabio Mascarenhas

Check calling conventions. Windows .NET uses STDCALL while the default for
the C compiler is CDECL, this messes things up when a C function calls a
.NET function (and make sure you're setting the CallingConvention attribute
of P/Invoked functions, too). I had the exact same problem writing a binding
from .NET to Lua. :)

The problem goes away with Rotor (the shared source CLR) on FreeBSD... the
default there is CDECL. Why Microsoft didn't use this more sensible default
for the Windows .NET is beyond me.

Fabio Mascarenhas
(e-mail address removed)

----- Original Message -----
From: "Tim Sutherland" <[email protected]>
Newsgroups: comp.lang.ruby
To: "ruby-talk ML" <[email protected]>
Sent: Tuesday, August 05, 2003 2:58 AM
Subject: Re: Advocacy: Ruby on/with .net

Tim Sutherland wrote: said:
Yes, that is how I am doing it. NB: I'm planning to make the first
'real' release of my rubydotnetproxy library by the upcoming Monday.
[...]

Monday has passed and I haven't released...I've been battling one bug
for a number of days - when I call one C# method, bad stuff appears to be
happening with the stack pointer. Hopefully it's just a bug somewhere in my C
code which can easily be fixed once found.
 
T

Tim Sutherland

Fabio Mascarenhas said:
Check calling conventions. Windows .NET uses STDCALL while the default for
the C compiler is CDECL, this messes things up when a C function calls a
.NET function (and make sure you're setting the CallingConvention attribute
of P/Invoked functions, too). I had the exact same problem writing a binding
from .NET to Lua. :)

The problem goes away with Rotor (the shared source CLR) on FreeBSD... the
default there is CDECL. Why Microsoft didn't use this more sensible default
for the Windows .NET is beyond me.
[...]

Wow! Thank you thank you thank you! That was the problem. I haven't done
much C programming on Windows, so I didn't even know about these
different calling conventions.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top