Skip to content

Polyglot does not allow ruby to add methods to Java classes.  #3139

Open
@hymanroth

Description

@hymanroth

As suggested by @eregon in this StackOverflow question https://stackoverflow.com/questions/76567012/extending-monkey-patching-java-classes-in-truffle-ruby, I am opening an issue here.

We are currently checking the feasibility of porting a large Java/JRuby project to Truffle/GraalVM and we've hit a major problem with so-called monkey patching of Java classes in Ruby, which JRuby allows but Truffle does not. @eregon suggested that if the Java classes implement the "correct" interfaces then the polyglot api will convert additional ruby methods (eg [] or []=) to Java calls automatically.

Unfortunately this is not going to work for us, as I imagine it possibly won't for other large JRuby projects looking to port. The problem is as follows: over the course of 10 years and thousands of lines of code, the ruby programmers generally didn't interface with the Java programmers to add domain specific methods to their Java classes. They just implemented them themselves by monkey patching the Java classes directly in JRuby. This was both an agile and a "clean" approach, because the Java class was kept generic and free from project-specific extensions.

The result is that for some Java classes we have ruby files with additional method definitions running to several hundred lines. There is no way we can justify refactoring the entire ruby code base to rework all of the references to these methods.

Finally, and just to emphasize that the approach taken by polyglot is elegant in theory but unfeasible in practice I will post the polyglot HashTrait for [] and its analog in our monkey patch file:

Polyglot:

def [](key)
  Truffle::Interop.read_hash_value_or_default(self, key, nil)
end

Our legacy code:

def [] (*keys)
  if keys.size == 2 && keys[0].instance_of?(Array)
    self.java_send :fgetObj, [java.lang.String[], java.lang.Object], keys[0].to_s.to_java(:string), keys[1]
  elsif keys.size > 1  
    self.java_send :fgetObj, [java.lang.String[]], keys.to_java(:string)
  elsif keys[0].instance_of? Array
     self.java_send :fgetObj, [java.lang.String[]], keys[0].to_s.to_java(:string)
  else  
     self.java_send :getObj, [java.lang.String], keys[0].to_s.to_java(:string) rescue nil
  end   
end

We can see no way round this at the moment and so will continue to use JRuby for our ruby environment and will use polyglot for our Python implementation, which has much less legacy code.

Metadata

Metadata

Assignees

Labels

polyglotUses multiple Truffle languages or host interop

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions