Is there a way to print a functional interface? - java

Suppose I have an interface:
public interface Function {
double function (double input);
}
Now, suppose I have created an instance of this interface somewhere in my main class,
Function f = (x) -> x;
How can I go about printing this function, in plain text?
So, something a bit like this:
int f (double x) {return x}
Running a .toString on this Function prints something like Main$1#6d06d69c. How can I go about getting the java representation of this interface?

Remember that the text of a function (otherwise known as "code") only exists when you write it. You compile this to bytecode which is then run on the Java Virtual Machine. At runtime, the original code which you wrote no longer exists and cannot be easily retrieved.

Unfortunately, the answer (as of Java 9) is that there isn't a simple way to get the toString() method to give you a human-meaningful value for an arbitrary instance of a functional interface.
Here are a couple of alternatives that are applicable for some use-cases:
Instead of using a lambda, implement the interface using a class, and include an appropriate override for the toString() method.
Populate a Map<Function, String> with meaningful names for all of your Function instances.
It would be theoretically possible to build a library that can retrieve the ".class" file for (say) a lambda, analyse it, work out what the bytecodes do, and then produce an appropriate summary. But it would be difficult project.
It would be nice if there was a simple, clean solution to this. Maybe "someone" could suggest it as an RFE for a future version of Java.

You need to call the method in the interface explicitly by supplying a value of double, like below
Function f = (d) -> d;
System.out.print(f.function(2.0));

Related

Override a function type in sub type Kotlin/Java

I have this interface:
// Interface for any simulation that is integrated against dt
interface SimulationState {
fun integrate(totalTime: Long, deltaTime: Long) : SimulationState
fun interpolate(alpha: Double, previousState: SimulationState) : SimulationState
fun preRender() : Collection<Pair<Int, Int>>
}
The implementation is irrelevant to my question in this case. The question is can I override the function types in a sub type. Below is an example, that doesn't compile; hence my reason for asking this question.
interface ShipState : SimulationState {
// Still in abstract, just hope I can somehow override the function type...
override fun integrate(totalTime: Long,
deltaTime: Long,
asteroidVectors: Collection<Pair<Double, Double>>) : SimulationState
}
Hopefully the admittedly not compiling code above makes clear my intent. Is this possible with Java/Kotlin? If so, how would I go about it?
JVM object structure has an inner pointer to a table of methods available. When you call the method of the object, JVM access this table (let's call it vtable) and, if method is found, it executes it. But what to do if method is not found there? Then it tries to find this method in parent class. These accesses may be detected during compilation, which helps to avoid really complex problems with debugging on runtime.
Now, lets imagine that your example is possible. You have a class which implements ShipState and, through it, it also implements SimulationState. You implement your method integrate from interface ShipState (the one with 3 parameters).
But wait, your object is still of type SimulationState, right? Now let's imagine that you want to create a collection of simulations and process them in single way:
val simpleSimulation = SimulationStateImpl() //imaginary implementation of base interface
val shipSimulation = ShipSimulationImpl() // again imaginary implementation
val simulations = listOf<SimulationState>(simpleSimulation, shipSimulation)
simulations.forEach { it.integrate(totalTime = 100, deltaTime = 50) }
What happens next? On first iteration, everything is fine. When you call integrate on simpleSimulation JVM access it's vtable, finds implementation of integrate with two parameters and calls it. Fine.
On second iteration, JVM access vtable of object shipSimulation. It tries to resolve method integrate with two parameters and doesn't find it. Okay, what to do next? There are similar method which has three parameters, should we call it? If yes, which parameter do we need to pass? null? Why? What to do in case if your similar method has 5 parameters more? Compiler and runtime are not able to resolve this issues, that's why it's failing.
In terms of Java/Kotlin OOP, what you want to do is not an override. You just adding new method to a new interface, which, by coincidence, looks pretty similar to the other one. However this coincidence doesn't mean that it's same method.
Please take a look on this wonderful article, which explains topic in low-level details.
Probably you need not override but overload.
If yes, just remove keyword override from the derived interface.
If you need override (you are going to use polymorphism) both functions must have the same signature.
It is impossible to override the function:
(Long, Long) -> SimulationState
with function:
(Long, Long, Collection) -> Unit

Java equivalent of Javascript prototype

In JavaScript, you can do this.
String.prototype.removeNumericalCharacters = function(){
...code...
}
or
Number.prototype.addTwo = function(){
...code...
}
var a = 5;
a.addTwo();
//a is now 7
Is there a way to do something similar in Java? (I don't mean the actual function, just using that as an example)
An example in Java would be
int a = 5;
a.addTwo();
//A is now 7
My question is how do I define the .addTwo() method.
It's Friday so lets answer this question. I'm not going to dive into much details (it's Friday!) but hopefully you'll find this useful (to some extend).
You certainly know that Java objects don't have prototypes. If you want to add a field or a method to a Java class you have two options. You either extend the existing class and add the method/ field to it like this:
public class A {
}
public class B extends A {
int addTwo () {...};
}
However that's not changing the parent class. Objects of class A in the example still have no method addTwo.
Second approach is to dynamically change the class (you could use things like javassist) and method/fields to it. It's all fine but to use these new methids/fields you'd have to use reflection. Java is strongly typed and needs to know about class's available methods and fields during the compile time.
Finally and that's when things get really rough - primitive types, in your instance int, are 'hardwired' into JVM and can't be changed. So your example
int a = 5;
a.addTwo();
is impossible in Java. You'd have more luck with dynamic languages on JVM (Groovy is one of them). They're usually support optional typing and allow dynamic method calls.
So enjoy Friday!

How to get JNI-style signature string for a field or method?

I am trying to inspect a Java class and automatically retrieve all of its methods and fields in a way that I can invoke them via JNI on Android. However, I can't figure out how to actually get the textual signature string programmatically; I know how to get it via javap -s from the command line but I would like to get it from within my program.
The closest I can find is using clazz.getMethods() to get the individual methods, and then Method.toGenericString() to get a human-readable string, but that string is formatted like the Java code signature (e.g. public int someMethod(int foo, java.lang.String bar)) when I really just want the JNI-style signature (e.g. (ILjava/lang/String;)I), as I will need that string to call getMethodID() from JNI and I already have a perfectly-good parser that parses those JNI signatures in the first place.
I could just manually maintain bindings for the classes I actually care about accessing from JNI, but I'd much rather just have everything handled as automatically as possible; less code is better, after all.
I did find ASM which provides helper methods for this, but it appears to be a bytecode generation framework and I am not sure if it will be compatible with Android.
Or, in other words, given the following class:
class SomeClass {
String foo(int bar) { return "This is foo " + bar; }
}
I want to create a class called ClassInspector which can do something like:
ClassInspector ci = new ClassInspector(SomeClass.class);
int n = ci.getMethodCount(); // returns 1
String name = ci.getMethodName(0); // returns "foo"
String sig = ci.getMethodSignature(0); // returns "(I)Ljava/lang/string;"
Which is to say that I want to be able to get the output of javap -s from within Java, so that I can call Java methods from the native side.
I had the same problem and I don't find a "clean" solution.
Finally, I decided to create a dummy class with same methods but declared as native.
Then I use javah to create the header file and I take the signature from that header file.
I know that it does not look nice... but I don't find a better option (except creating it "manually" based on the Method properties).

"Find usages" functionality as an IntelliJ plugin

I'm trying to find a way in IntelliJ IDEA to find all the usages of a few library method calls and classes in a particular project.
The goal is to compile a list of classes which make reference to these specific methods or classes.
How can I go about this, I can see there is a MethodReferencesSearch which looks like it could be helpful, however the search method requires an instance of PsiMethod.
How can I create an instance of PSI method that matches the method in a particular lib class (say I wanted to find all the usages of the concat(...) method in Java's String class
Basically I'm trying to build a plugin that will generate a graph of certain method calls from within a project. For example something that would graph a set of routes by looking for certain method calls in a library. I.e. if Class A calls x(T) with type class B and class B calls x(T) with type of Class C, I would have a graph that looks like A -> B -> C etc. Find usages is great, it just doesnt work well for my needs.
You can get the true PsiMethod by JavaPsiFacade.getInstance(...).findClass("java.lang.String", ...allScope(...)).findsMethodByName("concat", false)[0]. This method can then be passed to MethodReferenceSearch.
I am presuming that you can't guarantee that you have a usage of concat easily available (for example, at the user's cursor position in an open document).
A hacky way to do it would be to create a small, correct, self-contained java class in a String, like below:
class Nothing { String s = "a".concat("b"); }
Then, there is a way (if I remember correctly) to use IntelliJ to parse the class contained in this String, thereby giving you a PsiReference to the method you want to find usages on (in this case, concat).
Would this approach be useful to you?
If so, I can dig out a code example on how this can be done.

identifier rename in java program

I need to programmatically rename identifiers within a given scope, for example, a method in java program. For example, given the following java function:
public void doSomething(){
int x = 10;
int y = x * 2;
int z = x + y;
}
after renaming the variables (x to a, y to b, and z to c) I should obtain the following function:
public void doSomething(){
int a = 10;
int b = a * 2;
int c = a + b;
}
How can I programmatically implement such renaming of identifiers and their references?
I have been looking into Eclipse AST and Java Model. In either case I have to implement search for all occurrences of any given identifier, and then replace them. I am wondering if there is a better way to do this (how the Eclipse Refactoring UI supports such variable renaming)? Or, should I look into the Language Toolkit (org.eclipse.ltk.core.refactoring)? Any tutorial, sample code, or suggestion?
Please help.
I'm unclear as whether you wish to perform this renaming across the board (i.e. all methods in all classes) or just to specific classes which you would identify manually. Assuming the latter, I would recommend that you:
Use the Java reflection API java.lang.reflect to identify all methods defined within the particular class that requires local
variable renaming.
Iterate across all methods. For each method, use the org.eclipse.jdt.core API to descend through the hierarchy of compilation elements, selecting locally scoped variable definitions. Get the name of the variable for the
compilation unit.
Generate your new variable name. Something like: Old ==> OldRenamed. Apply whatever renaming heuristic you wish at this point.
Invoke the Eclipse development kit org.eclipse.jdt.ui.refactoring API methods to do the variable renaming
within the method. Effectively you would be invoking the Eclipse Rename Variable functionality
headlessly by using this API.
That should do the trick.
I am able to rename using the following code.
RenameSupport renameSupport = RenameSupport.create(field, newName, RenameSupport.UPDATE_REFERENCES);
renameSupport.perform(workbench.getShell(), workbench);
But it applies the changes to the actual source files. Is there Anyway that can be prevented? I just need the renamed code internally, must not change the actual source.
I really question the wisdom of doing this, but it can be done using an annotation processor. You will have to accept that the annotation processor can not modify existing source code but can create new source code that is basically a clone of the original (except for the renames).
Create annotations that define the search and replace.
Annotate your source code. You can create a source file package-info.java and annotate at the package level.
Your processor could use the Compiler Tree API via the Trees.instance method.
You could extend SimpleTreeVisitor to do the actual copying. It will be tedious, but not very complicated.
The only use case that I can think of for this is that you have prepared source code with variable names that make sense in human language A (e.g. Japanese) and you wish to discuss it with an audience (boss, students, clients, etc.) who are more comfortable with human language B (e.g. Arabic)
Other than that, I can not think of any good reason to go to so much trouble. In the example given, x, y, and z are are local variables. Since there scope is so small, there is really no pressing need to rename.
Select variable
Click right mouse button
Select refactor
Select rename
rename variable
Eclipse will rename this variable in all place it's used

Categories

Resources