ninia / jep

Embed Python in Java
Other
1.33k stars 151 forks source link

Jep doesn't consider naming conversions when calling Java methods #565

Open chlomaki1 opened 1 month ago

chlomaki1 commented 1 month ago

Describe the bug Right now, all methods have to be called using the exact same naming convention as they are defined with in Java, which while not exactly a bug; normal Java naming conventions violate that of which is standard for Python. Predominantly, Python methods use snake case in method declarations, whilst Java methods use camel case. This leads to an inconsistency when creating types for java classes, or utilizing them in python with other libraries that follow normal conventions.

Case in point, this stub typing I made for one of my own classes. Code_-_Insiders_WXx8ZFYchc

In normal scenarios, this inconsistent styling would be highly shunned upon. Is there any way this could be rectified, or worked around? I only labelled this as a bug because I wasn't sure whether to label it as a feature request, even though it is largely one.

bsteffensmeier commented 1 month ago

I think this is unnecessary. Although python style guides recommend snake case for method names there are exceptions even in the standard libraries(such as TestCase.setUp(), Logger.setLevel() and Element.findAll()). PEP8 even has an entire section emphasizing that t is not always best to follow the style guidelines and I believe that this is exactly the type of case for which that section was included. Many times I have copied code snippets directly from java to python and I find it quite nice that the same code can mostly run in both. It's also handy to be able to look up documentations for methods online based off the name as it appears in python, something that would become more difficult if we were to start renaming things.

With that being said I think this is an interesting technical challenge so I've explored some things you can do with the jep internals if you would like to customize your jep interpreters to use a different naming convention. Since this messes with internal things it is not guaranteed to be compatible with all future versions of jep but there aren't currently plans to change the internals so it will most likely continue to work.

If there are specific instances where a name is bothering you then you can access the python type representing the java class and rename methods, here is an example I ran in the jep interpreter:

>>> from java.util import ArrayList
>>> numbers = ArrayList(list(range(1,20)))
>>> numbers.indexOf(5)
4
>>> numbers.index_of(5)
'ArrayList' object has no attribute 'index_of'
>>> array_list_type = ArrayList.__pytype__
>>> type(numbers) is array_list_type
True
>>> array_list_type.index_of = array_list_type.indexOf
>>> numbers.index_of(5)
4

Now every ArrayList in the interpreter has an index_of method. Of course doing individual methods is tedious, but it isn't too hard to write code to automatically convert all the methods:

>>> for name in dir(ArrayList):
...   if not name.islower():
...       method = getattr(array_list_type, name)
...       name = ''.join(['_'+c.lower() if c.isupper() else c for c in name]).lstrip('_')
...       setattr(array_list_type, name, method)
... 
>>> numbers.is_empty()
False

The next step would be to put that code in a function and run it against all your favorite java classes when you setup your interpreter. The types are used for the life of the interpreter so any methods you name will work with all objects of that type in the interpreter.

It would be even better if you could automatically detect when new types are created for java classes. To start you could replace the JepJavaImporter in the meta_path with a custom wrapper that adds snake case attributes to the type, that would "fix" any python imports of java classes. Unfortunately when objects of java classes are returned from java methods they can create types without an import so that wouldn't catch all cases. You could probably start replacing all the java methods on java types with decorator methods that would check for new types and add snake_case methods to them, but at that point you might start hurting performance by slowing down function calls. Maybe you have a use case where snake case is more important than performance but for most cases I think it is better to just stick with the naming conventions of the language the class is written in.

chlomaki1 commented 1 month ago

An unfortunate, but understandable circumstance where I can definitively see retaining original conventions and ignoring standard is optimally better for compatibility with Java.

Albeit, this is something I do understand; and was more so initially wondering if an option for the likes could be made for the people who definitively know that the functions they make and libraries they use will function all the same no matter what convention they use and don't mind the potential cost of performance in favor of cohesion in-between sides.

My own use case is that of which each side are mostly independent but there's good interoperability between the two by self made library, where as to preserve conventions several wrapper functions are made around existing Java functions.