In Java maps when we need to insert some values then we use:
map.put(key, value);
In other languages such as with C++ maps or Python dictionaries we can use square brackets:
map['key'] = value
This syntax is not valid with Java maps. Can we change this syntax programmatically by writing some code or using some library?
In Java, you cannot. There are very few languages that allow customization of syntax. Perl, for example, has "pragmas" that are basically other Perl code that preprocesses your script before it runs. It's very powerful but also horrible.
If you need compatibility with Java but like nice syntax, I would suggest Kotlin instead, which (like C++ and Python) allows operator overloading.
Java's grammar cannot be altered at runtime nor at compile time, even operator overloading is not supported (with the exception of + operator overloaded for String. See: How does the String class override the + operator?).
You can overload symbolic operators (such as -,+, /) in other JVM languages such as Scala Groovy and Kotlin, but that's a predefined syntactic sugar, and the syntax itself is still unchanged.
One of the few languages which does allow to change syntax at runtime is Raku, slangs can be added to its grammar at runtime. An example of practical application of this feature is Slang::SQL which makes SQL part of the main syntax.
It would be possible to write a program that looked at your source code before the compiler sees it, and transforms map['key'] = value to map.put(key, value);. But that would likely be more work than makes sense to spend on this. And that doesn't even get into integrating into a build system.
More seriously, if you knew all the keys ahead of time, which I think you might since you used a string literal, you could get fairly similar syntax by using arrays:
Object[] map = new Object[10];
map[KEY] = value;
where key is an integer constant like
public static final int KEY = 0;
Hashmaps/Dictionaries do something similar under the hood.
Related
I'm new to Java and I couldn't find an answer to it anywhere because i don't even know how to search for it.
I want to define how 2 objects can be added together, so you get a new one like for example you can add String "a" and String "b" to get "ab".
I know this can be done in python by doing self.__add__(self, other).
How can you do this in Java?
The thing you are looking for is called operator overloading. It exists in some languages, however in Java it does not.
The best thing you can do is to define a method add() inside the class and then use it like this:
object1.add(object2);
I know it looks nicer with a + between them, but that would make compiling more complex.
With the exception of java.lang.String being treated as a special case1, Java does not allow you to define the behaviour of + for arbitrary types, or indeed any other operator, as you can in some languages such as C++ or Scala. In other words, Java does not support operator overloading.
Your best bet is to build functions like add &c. Appeal to precedent here: see how the Java guys have done it with BigInteger, for example. Sadly there is no way of defining the precedence of your functions, so you have to use very many parentheses to tell the compiler how you want an expression to be evaluated. It's for this reason that I don't use Java for any serious mathematical applications as the implementation of even a simple equation quickly becomes an unreadable mess2.
1 Which in some ways does more harm than good: e.g. consider 1 + 2 + "Hello" + 3 + 4. This compile time constant expression is a string type with the value 3Hello34.
2 Note that C++ was used to model the gravitational lensing effects of the wormhole in the movie "Interstellar". I challenge anyone to do that in a language that does not support operator overloading! See https://arxiv.org/pdf/1502.03808v1.pdf
Java does not allow you to override operators. String is a special case that does allow this functionality.
What you can do is add an add function like so:
public YourObject add(YourObject yourObject){
return new YourObject(this.propertyToAdd + yourObject.propertyToAdd);
}
Edit: I have rewritten the question to hopefully make it more understandable.
I do not want to overload!
If you have the following code:
ImmutableObject mutableReference = new ImuttableObject();
mutableReference = mutableReference.doStuff(args);
Can a compile time or pre-compile time process replace defined text formats? For example:
DEFINE X.=Y AS X = X.Y
could replace
mutableReference .= doStuff(args) with mutableReference = mutableReference.doStuff(args);
So some process knows that the code before ".=" is X and after is Y. Similar to syntactic sugar, before compiling or during, just replace X.=Y with X = X.Y.
Below is the old version of the question.
I have the following "form" of code for lack of a better word.
turnStates = turnStates.add(currentState); // log end of turn state.
//turnStates.=add(currentState);
//turnStates=.add(currentState);
Where turnStates can be a reference to any immutable object.
I would like it to look like the code commented out or similar.
Much like integers that have ++ and += I'd like a way to write my own for my immutables.
I think I recall some pre-processor stuff from C++ that I think could replace predefined text for code snippets. I was wondering if there was a way in java to define a process for replacing my desired code for the working code at compile time.
I'm sure you could make the IDE do it, but then you can't share the code with others not running a pre-configured IDE.
Edit:
turnStates is immutable and returns a different object on a call to add. It is test code and I have my reasons why a list, or as it is at the moment acting more like a stack, is immutable. Irrelevant for the question as I could simply replace it with
player = player.doSomething(args) where doSomething(args) returns a Player instance. Player is just a small part of the model and is costless to be immutable.
I know Overloads and syntax can't be changed in Java. As I tried to portray originally, sorry if it didn't come across this way is:
I was hoping that I wasn't aware of a syntax to do with maybe the # sign that could replace text before compiling. So for example:
DEFINE X.=Y AS X = X.Y where X = turnStates and Y = add() in my example.
But as the answer I upvoted said. I'll check out Scala as the answer seems to be no.
No. Java explicitly does not support operator overloading for user defined data types. However, scala is a JVM hosted language and does.
Unlike C++,Java doesn't support operator overloading.But Scala or Groovy does.
Scala can be integrated into Java but the operator overloading integration part is still not directly supported by Java as you will not be able to use the operator itself but something like #eq(...) for the "=" operator.
Check this link out for a little more detail if you want to know about Scala integration into java
Bottom line:
operator overloading is not supported by Java
And if your project requires a lot of vector addition, substraction,etc. i.e. lot of custom operators then a good suggestion would be using C# as your choice of language which is a Java like language
At a lower level, what kind of changes were made by java 8 to incorporate a new operator "->", though I understand that in normal programming practice we can't overload any existing operator as like in C++.
You are completely on the wrong track when you think that the “JVM understands” the operators of the Java language. These operators are purely a source code artifact that gets translated to Java byte code by the compiler. For example, in Java source code you can use the operator + to concatenate Strings since the very first version, but the Java byte code never had a direct support for it (up to Java 9).
On the other hand, in the past, all major Java language releases were paired with an update of the JVM, so there never was a requirement for an older JVM to work with newer byte code. While Java 8’s lambda expressions use features already introduced with version 7 of the JVM, the release of Java 8 comes with an updated JVM, which is required for features like non-abstract methods in interfaces, so if lambda expression were requiring new byte code feature, it was no problem either.
That said, the grammar, which must be understood by the compiler rather than the JVM, has changed to add lambda expressions and method references. Therefore, you need an up to date compiler to use them. There is no DSL support inside Java source code. The closest thing to that, is using annotation based meta programming, but that’s far away from being able to add a new operator to the language.
I've got a bit of an interesting challenge
To the point:
I want to allow a user to enter an expression in a text field, and have that string treated as a python expression. There are a number of local variables I would like to make available to this expression.
I do have a solution though it will be cumbersome to implement. I was thinking of keeping a Python class source file, with a function that has a single %s in it. When the user enters his expression, we simply do a string format, and then call Jython's interpreter, to spit out something we can execute. There would have to be a number of variable declaration statements in front of that expression to make sure the variables we want to expose to the user for his expression.
So the user would be presented with a text field, he would enter
x1 + (3.5*x2) ** x3
and we would do our interpreting process to come up with an open delegate object. We then punch the values into this object from a map, and call execute, to get the result of the expression.
Any objections to using Jython, or should I be doing something other than modifying source code? I would like to think that some kind of mutable object akin to C#'s Expression object, where we could do something like
PythonExpression expr = new PythonExpression(userSuppliedText)
expr.setDefaultNamespace();
expr.loadLibraries("numPy", /*other libraries?*/);
//comes from somewhere else in the flow, but effectively we get
Map<String, Double> symbolValuesByName = new HashMap<>(){{
put("x1", 3.0);
put("x2", 20.0);
put("x3", 2.0);
}};
expr.loadSymbols(symbolValuesByName);
Runnable exprDelegate = expr.compile();
//sometime later
exprDelegate.run();
but, I'm hoping for a lot, and it looks like Jython is as good as it gets. Still, modifying source files and then passing them to an interpreter seems really heavy-handed.
Does that sound like a good approach? Do you guys have any other libraries you'd suggest?
Update: NumPy does not work with Jython
I should've discovered this one on my own.
So now my question shifts: Is there any way that from a single JVM process instance (meaning, without ever having to fork) I can compile and run some Python code?
If you simply want to parse the expressions, you ought to be able to put something together with a Java parser generator.
If you want to parse, error check and evaluate the expressions, then you will need a substantial subset of the functionality a full Python interpreter.
I'm not aware of a subset implementation.
If such a subset implementation exists, it is unclear that it would be any easier to embed / call than to use a full Python interpreter ... like Jython.
If the powers that be dictate that "thou shalt use python", then they need to pay for the extra work it is going to cause you ... and the next guy who is going to need to maintain a hybrid system across changes in requirements, and updates to the Java and Python / Jython ecosystems. Factor it into the project estimates.
The other approach would be to parse the full python expression grammar, but limit what your evalutor can handle ... based on what it actually required, and what is implementable in your project's time-frame. Limit the types supported and the operations on the types. Limit the built-in functions supported. Etcetera.
Assuming that you go down the Java calling Jython route, there is a lot of material on how to implement it here: http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
I watched the Oracle OTN Virtual Event: Java SE and JavaFX 2.0 (28 Feb 2012) and while talking about the new diamond operator (that Map<String, List<String>> myMap = new HashMap<>(); thing) the speaker mentioned that it was not as simpleto implement than one might think, as it is not a simple token replacement.
My question is why? Why can't be this implemented as simply taking the string from the variable's declaration and put it into the diamond operator?
I didn't implement it either, so I can only guess.
But usually the reason these things are more complex than they seem is that first inspection only looks at the most common (or most publicized) use case. In this case it's the one you mentioned. In theory that should be easy to specify exactly and it should be rather easy to implement in a compiler.
However, the diamond operator (which is not technically a operator, by the way) can be used in different ways as well:
someMethodWithGenericArguments(new HashMap<>());
new SomeGenericClass(new HashMap<>());
T foo = new SomethingRelatedToT<>(); // where T is a generic type parameter
In those cases a simple token replacement obviously no longer works, you need actual type inference involving real type analysis (i.e. it's on an entirely different abstraction level as a simple token replacement would be).
Something which Java doesn't do (which many languages have) is implied types based on usage. i.e. Java doesn't imply a require type based on how it is used.
e.g.
Type a = b;
The type of a and the type of b are independent and no assumptions are made about b based on the type of a.
MethodHandles are showing signs of supporting this. The return type use can be based on context, but this is a runtime feature.
In conclusion, my assumption is; It was hard to implement in Java because the language didn't support any like it. If the language used feature like this all the time, the approach to take would be understood (in term of defining a spec of how it should work) and supported by the tools in the compiler.