About Python-based libraries for Processing

Hi all,

I have a few questions regarding the feasibility and the viability of a library/module that would be implemented in Python but operable in both Java and Python mode.

  • Do you know about such library ?

  • Could it be possible to distribute a Python library as a JAR file with Jython ? (as discussed here)

    • if so, would the performance of such library be significantly impaired compared to a native Java library ?

    • if not, would a Processing Python library targeted at Python mode users only be considered as a Processing library by the community ? (officially referenced but with a mention “Python mode only” for example)

I am curious to hear your thoughts on this.

1 Like
  • Unfortunately Jython isn’t optimized like other JVM languages.
  • All Jython object properties are as if they were Java volatile fields.
  • Everything in Jython is an object. No primitive datatypes like Java.
  • We can do some workarounds like temporarily caching everything as local variables for example.
  • But even so the performance gap compared to a native Java (and even some other JVM languages) code is gonna be noticeable.
2 Likes
  • Jython code can be compiled & compressed as a “.jar” file indeed.
  • But we also have to consider how a Java code would see & use a Jython class.
  • In Java all classes implicitly inherits from class Object:
  • Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html
  • But in Jython, if we don’t specify, a class doesn’t inherit from any class by default.
  • From now on, everything I say is pure speculation, b/c I’ve never seen a Jython coded library yet.
  • So in order to be on the safer side, any exposed class should inherit from an already existing Java class or in the very least from the Object class.
  • That is, the 1 w/ capital “O”, not Jython’s object w/ lowercase “o”:
from java.lang import Object

class JythonClass(Object): pass
  • AFAIK, everything in Jython is a PyObject:
    PyObject (Jython API documentation)
  • Therefore anything we return from a Jython method is gonna be by default a PyObject derived datatype.
  • That surely wouldn’t be very practical for some1 using such a Jython class from within their Java code.
  • So this Jython class below:
from java.lang import Object

class JythonClass(Object):
    def __init__(self, someValue): self.val = someValue


    def intAdd(self, someValue):
        self.val += someValue
        return self.val


    def floatAdd(self, someValue):
        self.val += someValue
        return self.val * 1.0


    def strAdd(self, someValue):
        self.val += someValue
        return `self.val`


    def listAdd(self, someValue):
        self.val += someValue
        return [self.val]


    def toString(self): return `self.val`
  • I believe it would probably become something like this when accessed from the Java side:
import org.python.core.*;

public static class JythonClass {
  public int val;

  public JythonClass(int someValue) {
    val = someValue;
  }

  PyInteger intAdd(int someValue) {
    val += someValue;
    return new PyInteger(val);
  }

  PyFloat floatAdd(int someValue) {
    val += someValue;
    return new PyFloat(val);
  }

  PyString strAdd(int someValue) {
    val += someValue;
    return new PyString(str(val));
  }

  PyList listAdd(int someValue) {
    val += someValue;
    PyList pl = new PyList();
    pl.append(new PyInteger(val));
    return pl;
  }
  • That would demand more effort for the Java programmer to convert the returned datatype to another 1 more familiar:
    int intVal = jython.intAdd(50).asInt(); // explicit conversion method call
  • The method above intAdd() would probably return datatype PyInteger, not a Java primitive int:
    PyInteger (Jython API documentation)
  • So a Java programmer would need to know that a call to asInt() is necessary in order to store method intAdd()'s returned value to a Java int variable:
    PyInteger (Jython API documentation)
  • As a workaround we can convert a Jython datatype to a more common Java 1 before returning a value from a method:
from java.lang import Object, Integer, Float, String
from java.util import ArrayList

class JythonClassWorkaround(Object):
    def __init__(self, someValue): self.val = someValue


    def IntegerAdd(self, someValue):
        self.val += someValue
        return Integer(self.val)


    def FloatAdd(self, someValue):
        self.val += someValue
        return Float(self.val)


    def StringAdd(self, someValue):
        self.val += someValue
        return String(`self.val`)


    def ArrayListAdd(self, someValue):
        self.val += someValue
        return ArrayList([self.val])


    def toString(self): return String(`self.val`)
  • The class JythonClassWorkaround above would be much easier for a Java programmer IMO.
  • Probably it would be seen as something like this in Java:
import org.python.core.*;

public static class JythonClassWorkaround {
  public int val;

  public JythonClassWorkaround(int someValue) {
    val = someValue;
  }

  Integer IntegerAdd(int someValue) {
    val += someValue;
    return new Integer(val);
  }

  Float FloatAdd(int someValue) {
    val += someValue;
    return new Float(val);
  }

  String StringAdd(int someValue) {
    val += someValue;
    return new String(str(val));
  }

  ArrayList<Integer> ArrayListAdd(int someValue) {
    val += someValue;
    ArrayList<Integer> al = new ArrayList<Integer>(1);
    al.add(new Integer(val));
    return al;
  }

  String toString() {
    return new String(str(val));
  }
}
  • Here’s a Java test-drive for both classes:
import org.python.core.*;

JythonClass jython = new JythonClass(100);
JythonClassWorkaround jyJava = new JythonClassWorkaround(100);

int intVal;
float floatVal;
String strVal;
ArrayList<Integer> listVal;

void setup() {
  println(jython, jyJava); // 100 100

  intVal = jython.intAdd(50).asInt(); // explicit conversion method call
  println(intVal); // 150

  intVal = jyJava.IntegerAdd(-70); // auto-unboxing
  println(intVal); // 30

  floatVal = (float) jython.floatAdd(-30).asDouble(); // conversion method
  println(floatVal); // 120.0

  floatVal = jyJava.FloatAdd(20); // auto-unboxing
  println(floatVal); // 50.0

  strVal = jython.strAdd(-45).toString(); // explicit conversion method call
  println(strVal); // 75

  strVal = jyJava.StringAdd(10); // already a Java string
  println(strVal); // 60

  listVal = new ArrayList<Integer>(jython.listAdd(-35));
  println(listVal); // [40]

  listVal = jyJava.ArrayListAdd(23);
  println(listVal); // [83]

  exit();
}

P.S.: Jython’s javadoc: jython 2.7.3 javadoc (org.python)

2 Likes

Thank you so much for all the insights! The examples are really helpful.

I’ll probably give it a try in the coming weeks.

This is a really interesting idea. Could you say something about the motivation – a use case, or the target audience(s)?

For example, why not either

  1. just package the library as Java (then it can also be imported in python mode), or
  2. create two versions of the library, one in Python and one in Java
2 Likes

Jython version would be the source code version for code revision. :snake:
While the converted Java version would be the library deployment solution. :coffee:
Although any changes to the Jython version would need to be applied to the Java 1. :sweat:

1 Like

Hi Jeremy,

I can’t say much as it is nothing serious really. I was mostly being curious about the state of Python-based libraries for Processing.

However, if I ever take the leap I guess it would have to do with Computational Geometry. I think Processing is lacking major useful (and often simple) functions that even currently available libraries are missing. I would personally love to address this short-coming.

The target audience would be architecture students or design researchers. Python is a widespread language (along with C#) in this field of activity and I think it would make sense (at least from my point of view) to implement a module that would be easily portable to other Python-compatible and design-related environments.

It would also certainly be a great experience for a rookie like me to face the challenges of building my first library/module.

I try to do things to the best I can. If I ever code something that is meant to be used by others I would like it to be decently implemented, reasonably efficient and easily readable. I wish I could tell you I could do all of this in Java but the reality is that, at the present, it is way beyond my ability. I would prefer coming up with a toolkit whose impact is limited in terms of popularity (python-mode users only) but that does the job well rather than dashing off a weak and poorly-written piece of program for all.

1 Like

This makes sense to me. In the digital humanities python is also far more popular than Java – if I could write python libraries that worked in both modes I certainly would.

I have a library right now that I use with Python mode and wish it could work with Java without a rewrite. However it is hard to find time when I am immersed in both – two years ago I was spending almost all my time on the Python side, this past year I am spending a lot more time on the Java side…

1 Like

You still can code in Jython only and deploy the compiled library as a JAR file to the PDE.

However, as I had stated before, I’m afraid you may need to pay close attention to the datatype of any value you return to the user from Jython functions, in such a way that a Java user can easily store in a Java variable w/o so much hassle.

2 Likes

I know, your explanation was really enlightening and I am considering this option as well. Thanks again !

1 Like