Yann-Gaël Guéhéneuc
(/jan/, he/il)
Work licensed under Creative Commons
BY-NC-SA 4.0 International
Java is the New Python
(Or How to Open the World)
Version 0.9
25/03/05
2/172
Any questions/comments are welcome at
yann-gael.gueheneuc@concordia.ca
Source code available at
https://github.com/ptidejteam/tutorials-
JavaIsTheNewPython
3/172
Inspiration
 2025 Is the Last Year of Python Dominance
in AI: Java Comin’
– https://thenewstack.io/2025-is-the-last-year-of-
python-dominance-in-ai-java-comin/
 The Isthmus in the VM
– https://cr.openjdk.org/~jrose/panama/isthmus-in-
the-vm-2014.html
4/172
Observations
 Machine learning / AI has made some great
progress in recent years
 By coincidence, most libraries are written in
C++ or Python
5/172
Observations
C++
 Complexity of the syntax
 Complexity of the semantic
 Multiple ways to do the
same things
 No garbage collector
 No memory safety
Python
 Python is slow at runtime
 Cannot do mobile apps
 Difficult to use with other
languages
 High memory consumption
 Not used in enterprise
development
 Runtime errors
 Simplicity
https://www.geeksforgeeks.org/advantages-and-disadvantages-of-cpp/
https://www.geeksforgeeks.org/disadvantages-of-python/
6/172
Observations
 “However, enterprises are realizing that Java
is the better choice for enterprise-level
deployments. We’re likely to see Java
outpace Python within the next 18
months to three years.”
—Simon Ritter, deputy CTO,
Azul Systems, January 2025
7/172
Observations
 “However, enterprises are realizing that Java
is the better choice for enterprise-level
deployments. We’re likely to see Java
outpace Python within the next 18
months to three years.”
—Simon Ritter, deputy CTO,
Azul Systems, January 2025
Emphasis mine
8/172
Questions
 In Java
– How to best use existing libraries (C++, Python)?
– How to best use “new” hardware (GPUs)?
9/172
Questions
 In Java
– How to best open JVM’s closed world?
– How to best bridge memory models?
10/172
https://saf-astronomie.fr/listhme-de-penthievre-et-la-cote-sauvage/
Security
Managed memory
Garbage collection
Unmanaged memory
Unsecure
The Isthmus in the JVM
11/172
IN DETAILS
12/172
The Isthmus in the JVM
1. Syntax: lambdas vs. function pointers, no C macros, no C++ templates
2. Naming: naming and scoping
3. Data types: Booleans, strings, which always have headers
4. Storage management: many native libraries operate through pointers
to memory, garbage collection
5. Exceptions: C++ and Java exceptions behave differently; C APIs
sometimes require ad hoc polling for errors
6. Semantics: Java strings are immutable while C “strings” are character
arrays, C++ strings are yet different
7. Performance: strings, boxing, copying cause performance “potholes”
8. Safety: the JVM must continue to operate correctly even in the face of
errors or abuse of any single API
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
13/172
1. Syntax
 Java lambdas
 C/C++ function pointers
static void methodNeedingSomeComparator(
final BiFunction<Integer, Integer, Integer> aComparator) {
System.out.println(aComparator.apply(1, 2));
System.out.println(aComparator);
}
...
final BiFunction<Integer, Integer, Integer> max4 = Math::max;
Main.methodNeedingSomeComparator(max4);
System.out.println(max4);
typedef int (*fp_max_comparator)(const int, const int);
void function_needing_some_comparator(const fp_max_comparator comparator)
{
printf("%dn", compartor(1, 2));
}
int my_max_function(const int a, const int b) { ... }
...
function_needing_some_comparator(&my_max_function);
14/172
interface Executable {
int myMax(final int a, final int b);
}
class MyExecutable implements Executable {
public int myMax(final int a, final int b) {
return Math.max(a, b);
}
}
final MyExecutable max1 = new MyExecutable();
System.out.println(max1.myMax(1, 2));
class MySecondExecutable implements BiFunction<Integer, Integer, Integer> {
public Integer apply(final Integer a, final Integer b) {
return Math.max(a, b);
}
}
final MySecondExecutable max2 = new MySecondExecutable();
Syntax.methodNeedingSomeComparator(max2);
final BiFunction<Integer, Integer, Integer> max3 = new BiFunction<Integer, Integer, Integer>() {
public Integer apply(final Integer a, final Integer b) {
return Math.max(a, b);
}
};
Syntax.methodNeedingSomeComparator(max3);
final BiFunction<Integer, Integer, Integer> max4 = (final Integer a, final Integer b) ->
{ return Math.max(a, b); };
Syntax.methodNeedingSomeComparator(max4);
final BiFunction<Integer, Integer, Integer> max5 = Math::max;
Syntax.methodNeedingSomeComparator(max5);
15/172
interface Executable {
int myMax(final int a, final int b);
}
class MyExecutable implements Executable {
public int myMax(final int a, final int b) {
return Math.max(a, b);
}
}
final MyExecutable max1 = new MyExecutable();
System.out.println(max1.myMax(1, 2));
class MySecondExecutable implements BiFunction<Integer, Integer, Integer> {
public Integer apply(final Integer a, final Integer b) {
return Math.max(a, b);
}
}
final MySecondExecutable max2 = new MySecondExecutable();
Syntax.methodNeedingSomeComparator(max2);
final BiFunction<Integer, Integer, Integer> max3 = new BiFunction<Integer, Integer, Integer>() {
public Integer apply(final Integer a, final Integer b) {
return Math.max(a, b);
}
};
Syntax.methodNeedingSomeComparator(max3);
final BiFunction<Integer, Integer, Integer> max4 = (final Integer a, final Integer b) ->
{ return Math.max(a, b); };
Syntax.methodNeedingSomeComparator(max4);
final BiFunction<Integer, Integer, Integer> max5 = Math::max;
Syntax.methodNeedingSomeComparator(max5);
Can’t be used by the
method needing it…
16/172
1. Syntax
 Outputs and object types
2
net.ptidej.isthmus.Syntax$1MyExecutable@372f7a8d
2
net.ptidej.isthmus.Syntax$1MySecondExecutable@28a418fc
2
net.ptidej.isthmus.Syntax$1@1f32e575
2
net.ptidej.isthmus.Syntax$$Lambda/0x0000028e58001240@77459877
2
net.ptidej.isthmus.Syntax$$Lambda/0x0000028e58001470@33c7353a
17/172
2. Naming
Java
 Separation
C++
 No separation
public class Naming {
public int identifier = 0;
public int identifier() {
return 0;
}
}
class Naming {
public:
int identifier = 0;
void identifier() {
}
};
error: 'void Naming::identifier()'
conflicts with a previous declaration
18/172
2. Naming
Java
 No nesting
 Impact on visibility
C++
 Nesting
 No impact on visibility
package a.b;
public class X {
}
package b;
public class X {
}
public static void main(String[] args) {
System.out.println(a.b.X.class);
System.out.println(b.X.class);
}
namespace a {
namespace b {
int x = 0;
}
}
namespace b {
string x;
}
using namespace a;
void foo() {
b::x = 42;
}
error: reference to 'b' is ambiguous
19/172
2. Naming
Java
 Modules
C++
 No equivalent
– Maybe linker libs?
module isthmus.java {
requires java.logging;
}
package net.ptidej.isthmus;
import java.util.logging.Logger;
public class Main {
private static Logger java. Logging =
Logger.getLogger("net.ptidej.isthmus");
public static void main(final String[] args) {
Main.logger.fine("Hello, World!");
}
}
20/172
3. Data types
Java
 Booleans are their own
 Strings are immutable
C/C++
 Booleans are shorts
 Strings are mutable
bool a[5];
bool result;
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
result += a[i];
}
cout << endl << result << endl;
boolean a[] = new boolean[5];
for (int i = 0; i < 5; i++) {
System.out.println(a[i]);
}
string string1 = "Hello";
string string2 = ", World!";
string string3 = string1 + string2;
cout << string3 << endl;
string3[0] = 'Y';
cout << string3 << endl;
final String string1 = "Hello";
final String string2 = ", World!";
final String string3 = string1 + string2;
System.out.println(string3);
final StringBuilder string4 =
new StringBuilder(string3);
string4.setCharAt(0, 'Y');
System.out.println(string4);
21/172
3. Data types
Java
 Performance
 Generics
– Autoboxing
C/C++
 Performance
 Consistency
public interface IntFunction<R>
public interface ToIntFunction<T>
vs.
Predicate<int, int>
using namespace std;
void abssort(float *x, unsigned n) {
sort(x, x + n, [](float a, float b) {
return (abs(a) < abs(b)); });
}
22/172
3. Data types
Java
 Primitive types
 Objects and references
C/C++
 Primitive types
 Pointers
https://stackoverflow.com/questions/373419/whats-the-difference-between-
passing-by-reference-vs-passing-by-value
23/172
4. Storage management
Java
 Objects
 Garbage collection
C/C++
 Pointers
 Memory lifetime
https://www.baeldung.com/java-stack-heap
https://study.com/academy/lesson/program-memory-in-c-programming.html
vs.
24/172
5. Exceptions
Java
 NullPointerException
 Exceptions are objects and
thrown consistently
C/C++
 null values
– One of the purpose of Rust!
 Some errors must be
polled actively
int example_errno() {
const char *filename = "somefile.txt";
ifstream file(filename);
if (!file) {
switch (errno) {
case ENOENT:
cerr << "Error: File doesn't exist." << endl;
break;
...
default:
cerr << "Error: Cannot open file." << endl;
break;
}
return 1; // Some error happened
}
...
25/172
6. Semantics
 Classes vs. interfaces
 Package-only visibility
– Modules
– Sealing
 final vs. const
 Single vs. multiple-inheritance
– Virtual vs. non-virtual member functions
 …
https://www.cs.gordon.edu/courses/cs212/paperwork/Java-C++comparison.pdf
26/172
7. Performance
 “Code which uses Java primitives performs
on a par corresponding C code, but…”
 https://unriskinsight.blogspot.com/2014/06/fa
st-functional-goats-lions-and-wolves.html
https://www.oracle.com/java/technologies/performance-comparisons.html
27/172
7. Performance
 “Code which uses Java primitives performs
on a par corresponding C code, but…”
 https://unriskinsight.blogspot.com/2014/06/fa
st-functional-goats-lions-and-wolves.html
Many threats
to validity!
https://www.oracle.com/java/technologies/performance-comparisons.html
28/172
8. Safety
 No attacks from untrusted code
 No privilege escalation from untrusted code
 No crashes
 No leaks
 No hangs
 Rare outages
 No unguarded casts
29/172
8. Safety
 No attacks from untrusted code
 No privilege escalation from untrusted code
 No crashes
 No leaks
 No hangs
 Rare outages
 No unguarded casts
See later…
30/172
ANSWERS
31/172
Three-prong Approach
https://en.wikipedia.org/wiki/Valhalla
https://www.historyextra.com/period/ancient-history/babylon-babylonia-tower-babel-hanging-gardens-hammurabi/
https://www.georgeglazer.com/wpmain/product/where-atlantic-pacific-meet-the-panama-canal-to-day-birds-eye-view-by-richard-rummell-1914/
32/172
Three-prong Approach
https://en.wikipedia.org/wiki/Valhalla
https://www.historyextra.com/period/ancient-history/babylon-babylonia-tower-babel-hanging-gardens-hammurabi/
https://www.georgeglazer.com/wpmain/product/where-atlantic-pacific-meet-the-panama-canal-to-day-birds-eye-view-by-richard-rummell-1914/
33/172
Three-prong Approach
https://en.wikipedia.org/wiki/Valhalla
https://www.historyextra.com/period/ancient-history/babylon-babylonia-tower-babel-hanging-gardens-hammurabi/
https://www.georgeglazer.com/wpmain/product/where-atlantic-pacific-meet-the-panama-canal-to-day-birds-eye-view-by-richard-rummell-1914/
34/172
Three-prong Approach
https://en.wikipedia.org/wiki/Valhalla
https://www.historyextra.com/period/ancient-history/babylon-babylonia-tower-babel-hanging-gardens-hammurabi/
https://www.georgeglazer.com/wpmain/product/where-atlantic-pacific-meet-the-panama-canal-to-day-birds-eye-view-by-richard-rummell-1914/
35/172
Three-prong Approach
 Project Panama FFI
 Project Valhalla value class/objects
 Project Babylon code reflection
36/172
Project Panama
37/172
Foreign Function Interface
 Early access build from Project Valhalla
– https://jdk.java.net/jextract/
– JDK 22 + JExtract v6.47 (24/10/09)
38/172
Java Native Interface
 Write Java code with native methods
– And System.loadLibrary()
 Generate header file with javah
– javac -h since Java 10
 Implement the header file
 Compile the Java code
– Can be done earlier too
 Run the compile code
39/172
Java Native Interface
package net.ptidej.panama.jni;
public class Main {
static {
System.loadLibrary("net_ptidej_panama_jni_Main");
}
public static native int stringLength(final String s);
public static void main(final String[] args) {
final String s = "Hello, world!";
System.out.println(Main.stringLength(s));
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_ptidej_panama_jni_Main */
#ifndef _Included_net_ptidej_panama_jni_Main
#define _Included_net_ptidej_panama_jni_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_ptidej_panama_jni_Main
* Method: stringLength
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
#include <cstring>
#include "net_ptidej_panama_jni_Main.h"
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *env, jclass jc, jstring js) {
const char* s = env->GetStringUTFChars(js, NULL);
return strlen(s);
}
40/172
Java Native Interface
package net.ptidej.panama.jni;
public class Main {
static {
System.loadLibrary("net_ptidej_panama_jni_Main");
}
public static native int stringLength(final String s);
public static void main(final String[] args) {
final String s = "Hello, world!";
System.out.println(Main.stringLength(s));
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_ptidej_panama_jni_Main */
#ifndef _Included_net_ptidej_panama_jni_Main
#define _Included_net_ptidej_panama_jni_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_ptidej_panama_jni_Main
* Method: stringLength
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
#include <cstring>
#include "net_ptidej_panama_jni_Main.h"
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *env, jclass jc, jstring js) {
const char* s = env->GetStringUTFChars(js, NULL);
return strlen(s);
}
Opens a door in the JVM
41/172
Java Native Interface
package net.ptidej.panama.jni;
public class Main {
static {
System.loadLibrary("net_ptidej_panama_jni_Main");
}
public static native int stringLength(final String s);
public static void main(final String[] args) {
final String s = "Hello, world!";
System.out.println(Main.stringLength(s));
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_ptidej_panama_jni_Main */
#ifndef _Included_net_ptidej_panama_jni_Main
#define _Included_net_ptidej_panama_jni_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_ptidej_panama_jni_Main
* Method: stringLength
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
#include <cstring>
#include "net_ptidej_panama_jni_Main.h"
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *env, jclass jc, jstring js) {
const char* s = env->GetStringUTFChars(js, NULL);
return strlen(s);
}
Opens a door in the JVM
JVM jargon
42/172
Java Native Interface
package net.ptidej.panama.jni;
public class Main {
static {
System.loadLibrary("net_ptidej_panama_jni_Main");
}
public static native int stringLength(final String s);
public static void main(final String[] args) {
final String s = "Hello, world!";
System.out.println(Main.stringLength(s));
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class net_ptidej_panama_jni_Main */
#ifndef _Included_net_ptidej_panama_jni_Main
#define _Included_net_ptidej_panama_jni_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: net_ptidej_panama_jni_Main
* Method: stringLength
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
#include <cstring>
#include "net_ptidej_panama_jni_Main.h"
JNIEXPORT jint JNICALL
Java_net_ptidej_panama_jni_Main_stringLength
(JNIEnv *env, jclass jc, jstring js) {
const char* s = env->GetStringUTFChars(js, NULL);
return strlen(s);
}
Opens a door in the JVM
JVM jargon
JVM C API
43/172
Java Native Interface
 gcc -Wl,--add-stdcall-alias
-shared -I"${JAVA_HOME}"/include
-I"${JAVA_HOME}"/include/win32
-o net_ptidej_panama_jni_Main.dll
net_ptidej_panama_jni_Main.cpp
 java net.ptidej.panama.jni.Main
– Prints 13
44/172
Java Native Interface
 Possible bug in the JVM
– “JVM Segmentation Fault with Single-file Source-code
Program and JNI”
• java Main.class will throw (correctly)
java.lang.UnsatisfiedLinkError
• java Main.java will also throw (correctly)
java.lang.UnsatisfiedLinkError
• But delete Main.class and java Main.java either throws
(correctly) java.lang.UnsatisfiedLinkError or writes
Segmentation fault without further info. or freezes and
must be killed
https://easydrawingguides.com/how-to-draw-a-ladybug-really-easy-drawing-tutorial/
45/172
Java Native Interface
 Limitations
– Sits between the two “worlds”
• Some code in Java, some code in C/C++
– Needs marshalling/mapping of data types
– Requires careful idioms
– Could crash the JVM
• Cf. possible Segmentation fault
– Lots of boiler-plate code
46/172
java.lang.foreign.Linker
 Focus on memory
 Increase amount of Java code
 Remove all C boiler-plate code
47/172
java.lang.foreign.Linker
public class Main {
public static void main(final String[] args) throws Throwable {
final Linker linker = Linker.nativeLinker();
final SymbolLookup dll = SymbolLookup.libraryLookup(
"net_ptidej_panama_version2_Main.dll", Arena.global());
final MethodHandle strlen = linker.downcallHandle(
dll.find("stringLength").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
try (final Arena arena = Arena.ofConfined()) {
final MemorySegment cString = arena.allocateFrom("Hello, World!");
final long length = (long) strlen.invoke(cString);
System.out.println(length);
}
}
}
#include <cstring>
#include "net_ptidej_panama_version2_Main.h"
long stringLength(const char *s) {
return strlen(s);
}
48/172
java.lang.foreign.Linker
public class Main {
public static void main(final String[] args) throws Throwable {
final Linker linker = Linker.nativeLinker();
final SymbolLookup dll = SymbolLookup.libraryLookup(
"net_ptidej_panama_version2_Main.dll", Arena.global());
final MethodHandle strlen = linker.downcallHandle(
dll.find("stringLength").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
try (final Arena arena = Arena.ofConfined()) {
final MemorySegment cString = arena.allocateFrom("Hello, World!");
final long length = (long) strlen.invoke(cString);
System.out.println(length);
}
}
}
#include <cstring>
#include "net_ptidej_panama_version2_Main.h"
long stringLength(const char *s) {
return strlen(s);
}
Much simpler and
“natural” C code
49/172
java.lang.foreign.Linker
 Linker
– nativeLinker()
 SymbolLookup
– libraryLookup()
 MethodHandle
– invoke()
 Arena
– global()
– ofConfined()
 MemorySegment
– allocateFrom()
 ABI (Application Binary Interface)
– Linker for the ABI of the native platform
 A symbol is a named entity
– Loads a library, creates a lookup
 A typed, executable entity
– Invokes the method handle
 Controls the life of native memory
– Program-long, thread-friendly, zeroed
– Temporary, zeroed
 A contiguous region of memory
– New memory segment initialised with
the provided, converted value
50/172
java.lang.foreign.Linker
 Advantages
– Simpler, natural C code
– More Java code
 Limitations
– Must handle manually the foreign library
51/172
java.lang.foreign.Linker
public class Main {
public static void main(final String[] args) throws Throwable {
final Linker linker = Linker.nativeLinker();
final SymbolLookup stringh = linker.defaultLookup();
final MethodHandle strlen = linker.downcallHandle(
stringh.find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG,
ValueLayout.ADDRESS));
try (final Arena arena = Arena.ofConfined()) {
final MemorySegment cString = arena.allocateFrom("Hello, World!");
final long length = (long) strlen.invokeExact(cString);
System.out.println(length);
}
}
}
52/172
java.lang.foreign.Linker
public class Main {
public static void main(final String[] args) throws Throwable {
final Linker linker = Linker.nativeLinker();
final SymbolLookup stringh = linker.defaultLookup();
final MethodHandle strlen = linker.downcallHandle(
stringh.find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG,
ValueLayout.ADDRESS));
try (final Arena arena = Arena.ofConfined()) {
final MemorySegment cString = arena.allocateFrom("Hello, World!");
final long length = (long) strlen.invokeExact(cString);
System.out.println(length);
}
}
}
Default lookup
53/172
java.lang.foreign.Linker
public class Main {
public static void main(final String[] args) throws Throwable {
final Linker linker = Linker.nativeLinker();
final SymbolLookup stringh = linker.defaultLookup();
final MethodHandle strlen = linker.downcallHandle(
stringh.find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG,
ValueLayout.ADDRESS));
try (final Arena arena = Arena.ofConfined()) {
final MemorySegment cString = arena.allocateFrom("Hello, World!");
final long length = (long) strlen.invokeExact(cString);
System.out.println(length);
}
}
}
Default lookup
For a known C function
54/172
java.lang.foreign.Linker
 Advantages
– Simpler, natural C code
– Less Java code
 Limitations
– Boiler-plate Java code
55/172
Project Valhalla
56/172
Value Classes and Objects
 Early access build from Project Valhalla
– https://jdk.java.net/valhalla/
– (Partial) JDK 23 + Valhalla
57/172
Java Split Personalities



58/172
Java Split Personalities
 Everything is an Object


59/172
Java Split Personalities
 Everything is an Object
 Except for primitive types
– Eight of them: boolean, byte, char, short, int,
long, float, double

60/172
Java Split Personalities
 Everything is an Object
 Except for primitive types
– Eight of them: boolean, byte, char, short, int,
long, float, double
 Except for arrays
– Class of Object[] is [Ljava.lang.Object;
61/172
Java Split Personalities
 Everything is an Object
 Except for primitive types
– Eight of them: boolean, byte, char, short, int,
long, float, double
 Except for arrays
– Class of Object[] is [Ljava.lang.Object;
62/172
Performance Costs
 These exceptions were a good idea
– In 1995
• Memory fetch ≈ Computation like addition
 But circumstances have changed
– In 2025
• Cache miss ≈ 1,000 × computation like addition
• Significant different relative cost
63/172
 Heap allocation
– Memory indirections
– Need flat (cache-efficient) and dense
(memory-efficient) data representation
 By-reference parameters
– Pointer dereferencing
– Need flat(ter) calling convention to pass
components by values
Performance Costs
64/172
Development Costs
 Generics
– Simpler, consistent APIs
– Primitive types wrinkles
 Autoboxing
– Loose identity, gain random identity
– Irregularity and cost
– Gotchas
public interface IntFunction<R>
public interface ToIntFunction<T>
vs.
Predicate<int, int>
65/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
66/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
NullPointerException
67/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
68/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
Never null (even if missing)
69/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
70/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
Prints
i = 1
d = 2.0
o1 = 1
o2 = 1.0
false
71/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
72/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
Prints
1.
2.
3.
73/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
74/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
The method f(Object,
boolean) is ambiguous
75/172
(Gotchas)
try {
final Integer a = null;
System.out.println("a = " + a);
final int b = a;
System.out.println("b = " + b);
}
catch (final NullPointerException e) {
}
{
final ResultSet rs = this.doSomeDatabaseQuery();
final Double value = rs.getDouble("someDoubleField");
}
{
final Integer i = new Integer(1);
final Double d = new Double(2.0);
System.out.println("i = " + i);
System.out.println("d = " + d);
final Object o1 = i;
System.out.println("o1 = " + o1);
final Object o2 = true ? i : d;
System.out.println("o2 = " + o2);
System.out.println(o1.equals(o2));
}
{
final int smallNumberInt = 42;
if (smallNumberInt == 42)
System.out.println("1.");
final Integer smallNumberInteger = Integer.valueOf(42);
if (smallNumberInteger == (Object) 42)
System.out.println("2.");
final int largeNumberInt = 500;
if (largeNumberInt == 500)
System.out.println("3.");
final Integer largeNumberInteger = Integer.valueOf(500);
if (largeNumberInteger == (Object) 500)
System.out.println("4.");
}
{
final int value = 42;
final Vector v = new Vector();
v.add(value);
System.out.println("first = " + v.getFirst().getClass());
Main.f(value, false);
}
private static void f(final Object a, final boolean b) {
System.out.println("f(Object a, boolean b)");
}
private static void f(final Object a, final Object b) {
System.out.println("f(Object a, Object b)");
}
76/172
Root Cause
 Identity
– All instances (and all
classes) are uniquely
identified
77/172
Root Cause
 Identity
– All instances (and all
classes) are uniquely
identified
final int i1 = 42;
final int j1 = 42;
System.out.println(i1 == j1);
final Integer i2 = Integer.valueOf(42);
final Integer j2 = Integer.valueOf("42");
System.out.println(i2 == j2);
System.out.println(System.identityHashCode(i2));
System.out.println(System.identityHashCode(j2));
final String s1 = "Hello, World!";
final String s2 = "Hello, Wordl!";
System.out.println(s1 == s2);
final ClassLoader cl1 = Main.class.getClassLoader();
final Class<?> c1 = cl1.loadClass("net.....Main");
final ClassLoader cl2 = Main.class.getClassLoader();
final Class<?> c2 = cl2.loadClass("net.....Main");
final MyClassLoader cl3 = new MyClassLoader();
final Class<?> c3 = cl3.findClass("net.....Main");
System.out.println(c1 == c2);
System.out.println(c1 == c3);
78/172
Root Cause
 Identity
– All instances (and all
classes) are uniquely
identified
final int i1 = 42;
final int j1 = 42;
System.out.println(i1 == j1);
final Integer i2 = Integer.valueOf(42);
final Integer j2 = Integer.valueOf("42");
System.out.println(i2 == j2);
System.out.println(System.identityHashCode(i2));
System.out.println(System.identityHashCode(j2));
final String s1 = "Hello, World!";
final String s2 = "Hello, Wordl!";
System.out.println(s1 == s2);
final ClassLoader cl1 = Main.class.getClassLoader();
final Class<?> c1 = cl1.loadClass("net.....Main");
final ClassLoader cl2 = Main.class.getClassLoader();
final Class<?> c2 = cl2.loadClass("net.....Main");
final MyClassLoader cl3 = new MyClassLoader();
final Class<?> c3 = cl3.findClass("net.....Main");
System.out.println(c1 == c2);
System.out.println(c1 == c3);
true
true
617901222
617901222
false
true
false
79/172
Solution
 Identity-less instances
– Value classes
– Value objects
“Codes like a class, works like an int.”
80/172
Value Classes
public value class Substring implements CharSequence {
private String str;
private int start;
private int end;
public Substring(final String str, final int start, final int end) {
Substring.checkBounds(start, end, str.length());
this.str = str;
this.start = start;
this.end = end;
}
public int length() {
return this.end - this.start;
}
public char charAt(final int i) {
Substring.checkBounds(0, i, length());
return str.charAt(start + i);
}
public Substring subSequence(final int s, final int e) {
Substring.checkBounds(s, e, length());
return new Substring(str, start + s, start + e);
}
public String toString() {
return str.substring(start, end);
}
private static void checkBounds(final int start, final int end, final int length) {
if (start < 0 || end < start || length < end) {
throw new IndexOutOfBoundsException();
}
}
}
81/172
Value Classes
public value class Substring implements CharSequence {
private String str;
private int start;
private int end;
public Substring(final String str, final int start, final int end) {
Substring.checkBounds(start, end, str.length());
this.str = str;
this.start = start;
this.end = end;
}
public int length() {
return this.end - this.start;
}
public char charAt(final int i) {
Substring.checkBounds(0, i, length());
return str.charAt(start + i);
}
public Substring subSequence(final int s, final int e) {
Substring.checkBounds(s, e, length());
return new Substring(str, start + s, start + e);
}
public String toString() {
return str.substring(start, end);
}
private static void checkBounds(final int start, final int end, final int length) {
if (start < 0 || end < start || length < end) {
throw new IndexOutOfBoundsException();
}
}
}
New keyword
82/172
Value Classes
public value class Substring implements CharSequence {
private String str;
private int start;
private int end;
public Substring(final String str, final int start, final int end) {
Substring.checkBounds(start, end, str.length());
this.str = str;
this.start = start;
this.end = end;
}
public int length() {
return this.end - this.start;
}
public char charAt(final int i) {
Substring.checkBounds(0, i, length());
return str.charAt(start + i);
}
public Substring subSequence(final int s, final int e) {
Substring.checkBounds(s, e, length());
return new Substring(str, start + s, start + e);
}
public String toString() {
return str.substring(start, end);
}
private static void checkBounds(final int start, final int end, final int length) {
if (start < 0 || end < start || length < end) {
throw new IndexOutOfBoundsException();
}
}
}
83/172
Value Classes
public value class Substring implements CharSequence {
private String str;
private int start;
private int end;
public Substring(final String str, final int start, final int end) {
Substring.checkBounds(start, end, str.length());
this.str = str;
this.start = start;
this.end = end;
}
public int length() {
return this.end - this.start;
}
public char charAt(final int i) {
Substring.checkBounds(0, i, length());
return str.charAt(start + i);
}
public Substring subSequence(final int s, final int e) {
Substring.checkBounds(s, e, length());
return new Substring(str, start + s, start + e);
}
public String toString() {
return str.substring(start, end);
}
private static void checkBounds(final int start, final int end, final int length) {
if (start < 0 || end < start || length < end) {
throw new IndexOutOfBoundsException();
}
}
}
Method call
before super()
84/172
Value Classes
public value class Substring implements CharSequence {
private String str;
private int start;
private int end;
public Substring(final String str, final int start, final int end) {
Substring.checkBounds(start, end, str.length());
this.str = str;
this.start = start;
this.end = end;
}
public int length() {
return this.end - this.start;
}
public char charAt(final int i) {
Substring.checkBounds(0, i, length());
return str.charAt(start + i);
}
public Substring subSequence(final int s, final int e) {
Substring.checkBounds(s, e, length());
return new Substring(str, start + s, start + e);
}
public String toString() {
return str.substring(start, end);
}
private static void checkBounds(final int start, final int end, final int length) {
if (start < 0 || end < start || length < end) {
throw new IndexOutOfBoundsException();
}
}
}
85/172
Value Classes
 Cannot compile with Eclipse
– Or any other current IDEs?
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/Substring.java
netptidejvalhallavalueclassSubstring.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value class Substring implements CharSequence {
^
netptidejvalhallavalueclassSubstring.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value class Substring implements CharSequence {
^
netptidejvalhallavalueclassSubstring.java:8: warning:
[preview] statements before super() is a preview feature and may be removed in a future release.
public Substring(final String str, final int start, final int end) {
^
3 warnings
86/172
Value Classes
 The class is implicitly final […]
 All instance fields are implicitly final […]
 The class does not extend an identity class
or an identity interface
 All constructors are implicitly regulated, […],
limiting use of this […]
 No instance methods are […] synchronised
 (Possibly) The class does not declare a
finalize() method
87/172
Value Classes
public static void main(final String[] args) {
final Substring subs1 = new Substring("Hello, World!", 7, 13);
System.out.println(subs1);
final Substring subs2 = new Substring("Hello, World!", 7, 13);
System.out.println(subs1);
System.out.println(Modifier.isIdentity(Substring.class.getModifiers()));
System.out.println(subs1 == subs2);
}
88/172
Value Classes
World!
World!
false
true
public static void main(final String[] args) {
final Substring subs1 = new Substring("Hello, World!", 7, 13);
System.out.println(subs1);
final Substring subs2 = new Substring("Hello, World!", 7, 13);
System.out.println(subs1);
System.out.println(Modifier.isIdentity(Substring.class.getModifiers()));
System.out.println(subs1 == subs2);
}
89/172
Value and Identity
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
90/172
Value and Identity
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java
netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected
public identity interface ICounter {
^
1 error
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface
public value interface IJSONValue {
^
1 error
2 warnings
91/172
Value and Identity
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java
netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected
public identity interface ICounter {
^
1 error
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface
public value interface IJSONValue {
^
1 error
2 warnings
92/172
Value and Identity
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java
netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected
public identity interface ICounter {
^
1 error
$ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: warning:
[preview] value classes are a preview feature and may be removed in a future release.
public value interface IJSONValue {
^
netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface
public value interface IJSONValue {
^
1 error
2 warnings
Not yet implemented
93/172
Value and Identity
 By default, an interface may be implemented
by both value classes and identity classes
 [If an] interface is only meant for one kind of
class or the other
 “It is an error for a value class or interface to
extend an identity class or interface […]”
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
94/172
Value and Identity
 By default, an interface may be implemented
by both value classes and identity classes
 [If an] interface is only meant for one kind of
class or the other
 “It is an error for a value class or interface to
extend an identity class or interface […]”
public identity interface ICounter {
int getValue();
void increment();
}
public value interface IJSONValue {
String toJsonString();
}
New keywords
95/172
Value and Identity
 Special considerations
– A functional interface, compatible with lambda
expressions, must allow for both value and
identity implementations
– An abstract class must allow for both value
classes and identity classes by default
– The class Object is special
• A concrete class
• Not an identity class
• Supports both identity and value subclasses
96/172
Regulated Constructors
 Compiler error
– Reading an instance field of the class
– Invoking an instance method of the class
– Using this, except in an assignment
– Using super to access a field or method
– Instantiating an inner class with this as
enclosing instance
– Calling explicitly a non-regulated constructor
(super() or this())
97/172
Regulated Constructors
 Compiler error
– Reading an instance field of the class
– Invoking an instance method of the class
– Using this, except in an assignment
– Using super to access a field or method
– Instantiating an inner class with this as
enclosing instance
– Calling explicitly a non-regulated constructor
(super() or this())
Weaker than the pre-
construction context, itself
weaker than the static context
98/172
Constructor Contexts
 Static
– “The purpose of a static context is to demarcate code that must not
refer explicitly or implicitly to the current instance of the class whose
declaration lexically encloses the static context. for which there is no
current instance defined of the class whose declaration lexically
encloses the static context.”
 Pre-construction
– “Unlike in a static context, an expression in a pre-construction
context is free, for example, to refer to the type of the instance under
construction.”
 Regulated
– “[A] constructor must not make any use of this in its body, except to
write to an instance field.”
https://docs.oracle.com/en/java/javase/22/docs/specs/statements-before-super-jls.html
https://openjdk.org/jeps/8277163
99/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
100/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
Static
101/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
Static
Pre-construction
102/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
Static
Pre-construction
Regulated
103/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
final B b = new B(42);
System.out.println(b);
Static
Pre-construction
Regulated
104/172
Constructor Contexts
class A {
}
class B extends A {
private String s;
private int i;
static {
System.out.println("Loading of B...");
}
{
System.out.println("Building of a B...");
this.s = "Omega";
}
B(final int a) {
System.out.println(a);
this.s = "Alpha";
super();
this.i = a;
}
@Override
public String toString() {
return this.s + " " + this.i;
}
}
final B b = new B(42);
System.out.println(b);
Loading of B...
42
Building of a B...
Omega 42
Static
Pre-construction
Regulated
105/172
Constructor Contexts
 Must enable preview features of Java
– javac --enable-preview -source 23 -cp
../bin/ -d ../bin/
net/ptidej/isthmus/constructor/contexts/*
– java --enable-preview
net.ptidej.isthmus.constructor.contexts.
Main
106/172
Caveats
 The == operator may treat two instances as the same,
where previously they were considered different
 Attempts to synchronize on an instance will fail, either at
compile time or run time
 The results of toString(), equals(), and hashCode(), if not
overridden, may change
 Assumptions about unique ownership of an instance may
be violated (e.g., an identical instance may be created at
two different times)
 Performance will generally improve, but may have
surprising different characteristics
107/172
Project Babylon
108/172
 Thanks to
Paul Sandoz
Juan Fumero
For their code and their help
109/172
Foreign Programming Models
 SQL
 GPUs
 Machine learning models
 Differentiable programming
 …
110/172
Example
f(x, y) = x × (-sin(x × y) + y) × 4


111/172
Example
f(x, y) = x × (-sin(x × y) + y) × 4
∂f(x, y)/∂x = (-sin(x × y) + y
- x × cos(x × y) × y) × 4
112/172
Requirements



113/172
Requirements
 Model of Java code


114/172
Requirements
 Model of Java code
 API to manipulate such model

115/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model
116/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model

117/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model
= Code Reflection
118/172
Enabling Code Reflection
 As of today
– Don’t even try on Windows
• Even with CygWin…
– Ubuntu 24.04.2 LTS x86_64
> sudo apt-get install autoconf libasound2-dev libcups2-dev libfontconfig1-dev
libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev
> sudo apt-get install sdkman
> sdk install java 23-open
> sdk use java 23-open
> git clone https://github.com/openjdk/babylon.git
> bash configure --with-boot-jdk=${JAVA_HOME}
> make images
> export JAVA_HOME=$ROOT_BABYLON/babylon/build/linux-x86_64-server-release/jdk
> export PATH=$JAVA_HOME/bin:$PATH
https://jjfumero.github.io/posts/2025/02/07/babylon-and-tornadovm
119/172
Enabling Code Reflection
 New javac/java versions
> java -version
openjdk version "24-internal" 2025-03-18
OpenJDK Runtime Environment (build 24-internal-adhoc.guehenyg.babylon)
OpenJDK 64-bit Server VN (build 24-internal-adhoc.guehenyg.babylon, mixed mode)
120/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model
121/172
Code (Meta-)Model
122/172
Code Model
@CodeReflection
public static double sub(final double a, final double b) {
return a - b;
}
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
System.out.println(subMethod);
final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get();
System.out.println(funcOp.toText());
funcOp.traverse(null, (acc, codeElement) -> {
int depth = 0;
CodeElement<?, ?> parent = codeElement;
while ((parent = parent.parent()) != null) {
depth++;
}
System.out.println(" ".repeat(depth) + codeElement.getClass());
return acc;
});
123/172
Code Model
@CodeReflection
public static double sub(final double a, final double b) {
return a - b;
}
class jdk.incubator.code.op.CoreOp$FuncOp
class jdk.incubator.code.Body
class jdk.incubator.code.Block
class jdk.incubator.code.op.CoreOp$VarOp
class jdk.incubator.code.op.CoreOp$VarOp
class jdk.incubator.code.op.CoreOp$VarAccessOp$VarLoadOp
class jdk.incubator.code.op.CoreOp$VarAccessOp$VarLoadOp
class jdk.incubator.code.op.CoreOp$SubOp
class jdk.incubator.code.op.CoreOp$ReturnOp
124/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model
125/172
API for Code Models
 Code models only exist for method
annotated with @CodeReflection
@CodeReflection
public static double sub(final double a, final double b) {
return a - b;
}
126/172
API for Code Models
Without @CodeReflection
 Size: 2,633 bytes
With @CodeReflection
 Size: 3,437 bytes
public static double sub(double, double);
descriptor: (DD)D
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
0: dload_0
1: dload_2
2: dsub
3: dreturn
LineNumberTable:
line 35: 0
public static double sub(double, double);
descriptor: (DD)D
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
0: dload_0
1: dload_2
2: dsub
3: dreturn
LineNumberTable:
line 35: 0
RuntimeVisibleAnnotations:
0: #109()
jdk.incubator.code.CodeReflection
127/172
API for Code Models
Without @CodeReflection
 Size: 2,633 bytes
With @CodeReflection
 Size: 3,437 bytes
public static double sub(double, double);
descriptor: (DD)D
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
0: dload_0
1: dload_2
2: dsub
3: dreturn
LineNumberTable:
line 35: 0
public static double sub(double, double);
descriptor: (DD)D
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=4, args_size=2
0: dload_0
1: dload_2
2: dsub
3: dreturn
LineNumberTable:
line 35: 0
RuntimeVisibleAnnotations:
0: #109()
jdk.incubator.code.CodeReflection
128/172
API for Code Models
With @CodeReflection
 Size: 3,437 bytes
public static jdk.incubator.code.op.CoreOp$FuncOp
op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double();
descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp;
flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: ldc #1
// String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double ->
{n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1
@"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double =
var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6
@loc="35:3";n};
2: invokestatic #3
// Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp:
(Ljava/lang/String;)Ljdk/incubator/code/Op;
5: checkcast #9
// class jdk/incubator/code/op/CoreOp$FuncOp
8: areturn
LineNumberTable:
line 1: 0
129/172
API for Code Models
With @CodeReflection
 Size: 3,437 bytes
public static jdk.incubator.code.op.CoreOp$FuncOp
op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double();
descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp;
flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: ldc #1
// String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double ->
{n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1
@"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double =
var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6
@loc="35:3";n};
2: invokestatic #3
// Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp:
(Ljava/lang/String;)Ljdk/incubator/code/Op;
5: checkcast #9
// class jdk/incubator/code/op/CoreOp$FuncOp
8: areturn
LineNumberTable:
line 1: 0
130/172
API for Code Models
With @CodeReflection
 Size: 3,437 bytes
public static jdk.incubator.code.op.CoreOp$FuncOp
op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double();
descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp;
flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: ldc #1
// String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double ->
{n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1
@"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double =
var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6
@loc="35:3";n};
2: invokestatic #3
// Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp:
(Ljava/lang/String;)Ljdk/incubator/code/Op;
5: checkcast #9
// class jdk/incubator/code/op/CoreOp$FuncOp
8: areturn
LineNumberTable:
line 1: 0
Parser of textually-
serialised code models
131/172
API for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
System.out.println(subMethod);
final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get();
System.out.println(funcOp.toText());
funcOp.traverse(null, (acc, codeElement) -> {
int depth = 0;
CodeElement<?, ?> parent = codeElement;
while ((parent = parent.parent()) != null) {
depth++;
}
System.out.println(" ".repeat(depth) + codeElement.getClass());
return acc;
});
@CodeReflection
public static double sub(final double a, final double b) {
return a - b;
}
132/172
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
System.out.println(subMethod);
final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get();
System.out.println(funcOp.toText());
funcOp.traverse(null, (acc, codeElement) -> {
int depth = 0;
CodeElement<?, ?> parent = codeElement;
while ((parent = parent.parent()) != null) {
depth++;
}
System.out.println(" ".repeat(depth) + codeElement.getClass());
return acc;
});
@CodeReflection
public static double sub(final double a, final double b) {
return a - b;
}
public static double net.ptidej.babylon.a.traversal.Main.sub(double,double)
func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double -> {
%2 : Var<double> = var %0 @"a" @loc="33:2";
%3 : Var<double> = var %1 @"b" @loc="33:2";
%4 : double = var.load %2 @loc="35:10";
%5 : double = var.load %3 @loc="35:14";
%6 : double = sub %4 %5 @loc="35:10";
return %6 @loc="35:3";
};
133/172
Requirements
 Model of Java code
 API to manipulate such model
 Interpreter to evaluate such model
134/172
Interpreter for Code Models
package jdk.incubator.code.interpreter;
public final class Interpreter {
private Interpreter() {
}
/**
* Invokes an invokable operation by interpreting the code elements within the
* operations body.
* <p>
* The sequence of arguments must [consist] of objects corresponding, in order,
* to the invokable operation's {@link Op.Invokable#parameters() parameters}. If
* the invokable operation {@link Op.Invokable#capturedValues() captures values}
* then the sequence of arguments must be appended with objects corresponding,
* in order, to the captured values.
*
* @param l the lookup to use for interpreting reflective operations.
* @param op the invokeable operation to interpret.
* @param args the invokeable's arguments appended with captured arguments, if any.
* @return the interpreter result of invokable operation.
* @param <T> the type of Invokable.
* @throws InterpreterException if there is a failure to interpret
* @throws Throwable if interpretation results in the throwing of an uncaught exception
*/
public static <T extends Op & Op.Invokable> Object invoke(MethodHandles.Lookup l, T op, Object... args) {
// ...
135/172
Interpreter for Code Models
 Yes, an equivalent of eval()!
– JavaScript
– Python
 In pure Java!
136/172
Interpreter for Code Models
final Method distanceMethod = Main.class.getDeclaredMethod(
"distance", double.class, double.class);
final CoreOp.FuncOp distanceFuncOp = Op.ofMethod(distanceMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(
MethodHandles.lookup(), distanceFuncOp, 10, 2);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp distanceFuncOpSSA = SSA.transform(distanceFuncOp);
final Double resultsInterpreted2 = (Double) Interpreter.invoke(
MethodHandles.lookup(), distanceFuncOpSSA, 42, 2);
System.out.println(resultsInterpreted2);
137/172
Interpreter for Code Models
final Method distanceMethod = Main.class.getDeclaredMethod(
"distance", double.class, double.class);
final CoreOp.FuncOp distanceFuncOp = Op.ofMethod(distanceMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(
MethodHandles.lookup(), distanceFuncOp, 10, 2);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp distanceFuncOpSSA = SSA.transform(distanceFuncOp);
final Double resultsInterpreted2 = (Double) Interpreter.invoke(
MethodHandles.lookup(), distanceFuncOpSSA, 42, 2);
System.out.println(resultsInterpreted2);
8
40
138/172
Interpreter for Code Models
https://www.pinterest.com/pin/697213586035124567/
139/172
Interpreter for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> {
final CopyContext cc = builder.context();
if (op instanceof CoreOp.SubOp subOp) {
final Op.Result inputResult = subOp.result();
final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast");
final Op.Result rhs = (Op.Result) cc.getProperty("last");
final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs));
cc.mapValue(inputResult, outputResult);
}
else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
final Op.Result result = builder.op(varLoadOp);
cc.putProperty("beforeLast", cc.getProperty("last"));
cc.putProperty("last", result);
}
else {
builder.op(op);
}
return builder;
});
final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10);
System.out.println(resultsInterpreted2);
140/172
Interpreter for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> {
final CopyContext cc = builder.context();
if (op instanceof CoreOp.SubOp subOp) {
final Op.Result inputResult = subOp.result();
final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast");
final Op.Result rhs = (Op.Result) cc.getProperty("last");
final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs));
cc.mapValue(inputResult, outputResult);
}
else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
final Op.Result result = builder.op(varLoadOp);
cc.putProperty("beforeLast", cc.getProperty("last"));
cc.putProperty("last", result);
}
else {
builder.op(op);
}
return builder;
});
final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10);
System.out.println(resultsInterpreted2);
141/172
Interpreter for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> {
final CopyContext cc = builder.context();
if (op instanceof CoreOp.SubOp subOp) {
final Op.Result inputResult = subOp.result();
final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast");
final Op.Result rhs = (Op.Result) cc.getProperty("last");
final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs));
cc.mapValue(inputResult, outputResult);
}
else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
final Op.Result result = builder.op(varLoadOp);
cc.putProperty("beforeLast", cc.getProperty("last"));
cc.putProperty("last", result);
}
else {
builder.op(op);
}
return builder;
});
final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10);
System.out.println(resultsInterpreted2);
22
142/172
Interpreter for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> {
final CopyContext cc = builder.context();
if (op instanceof CoreOp.SubOp subOp) {
final Op.Result inputResult = subOp.result();
final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast");
final Op.Result rhs = (Op.Result) cc.getProperty("last");
final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs));
cc.mapValue(inputResult, outputResult);
}
else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
final Op.Result result = builder.op(varLoadOp);
cc.putProperty("beforeLast", cc.getProperty("last"));
cc.putProperty("last", result);
}
else {
builder.op(op);
}
return builder;
});
final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10);
System.out.println(resultsInterpreted2);
22
143/172
Interpreter for Code Models
final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class);
final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get();
final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10);
System.out.println(resultsInterpreted1);
final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> {
final CopyContext cc = builder.context();
if (op instanceof CoreOp.SubOp subOp) {
final Op.Result inputResult = subOp.result();
final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast");
final Op.Result rhs = (Op.Result) cc.getProperty("last");
final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs));
cc.mapValue(inputResult, outputResult);
}
else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) {
final Op.Result result = builder.op(varLoadOp);
cc.putProperty("beforeLast", cc.getProperty("last"));
cc.putProperty("last", result);
}
else {
builder.op(op);
}
return builder;
});
final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10);
System.out.println(resultsInterpreted2);
22
42
144/172
Example
f(x, y) = x × (-sin(x × y) + y) × 4
∂f(x, y)/∂x = (-sin(x × y) + y
- x × cos(x × y) × y) × 4
145/172
Example
 Origin
@CodeReflection
static double f(final double x, final double y) {
return x * (-Math.sin(x * y) + y) * 4.0d;
}
static double df_dx(double x, double y) {
return (-Math.sin(x * y) + y - x * Math.cos(x * y) * y) * 4.0d;
}
146/172
Example
 Transformation
final Method f = Main.class.getDeclaredMethod("f", double.class, double.class);
final Double result_f1 = f(2, 3);
System.out.println(result_f1);
final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get();
final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f);
final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3);
System.out.println(result_f2);
final Double result_df_dx1 = df_dx(2, 3);
System.out.println(result_df_dx1);
final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0);
final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x));
final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3);
System.out.println(result_df_dx2);
147/172
Example
 Transformation
final Method f = Main.class.getDeclaredMethod("f", double.class, double.class);
final Double result_f1 = f(2, 3);
System.out.println(result_f1);
final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get();
final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f);
final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3);
System.out.println(result_f2);
final Double result_df_dx1 = df_dx(2, 3);
System.out.println(result_df_dx1);
final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0);
final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x));
final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3);
System.out.println(result_df_dx2);
148/172
Example
 Transformation
final Method f = Main.class.getDeclaredMethod("f", double.class, double.class);
final Double result_f1 = f(2, 3);
System.out.println(result_f1);
final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get();
final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f);
final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3);
System.out.println(result_f2);
final Double result_df_dx1 = df_dx(2, 3);
System.out.println(result_df_dx1);
final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0);
final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x));
final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3);
System.out.println(result_df_dx2);
The differentiation
happens here
149/172
final Method f = Main.class.getDeclaredMethod("f", double.class, double.class);
final Double result_f1 = f(2, 3);
System.out.println(result_f1);
final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get();
final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f);
final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3);
System.out.println(result_f2);
final Double result_df_dx1 = df_dx(2, 3);
System.out.println(result_df_dx1);
final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0);
final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x));
final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3);
System.out.println(result_df_dx2);
Example
 Results
– f(2, 3) = 2 × (-sin(2 × 3) + 3) × 4
= 26.235323985591407
– ∂f(2, 3)/∂x = (-sin(2 × 3) + 3 - 2 × cos(2 × 3) × 3) × 4
= -9.92642488681308
150/172
final Method f = Main.class.getDeclaredMethod("f", double.class, double.class);
final Double result_f1 = f(2, 3);
System.out.println(result_f1);
final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get();
final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f);
final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3);
System.out.println(result_f2);
final Double result_df_dx1 = df_dx(2, 3);
System.out.println(result_df_dx1);
final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0);
final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x));
final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3);
System.out.println(result_df_dx2);
Example
 Results
– f(2, 3) = 2 × (-sin(2 × 3) + 3) × 4
= 26.235323985591407
– ∂f(2, 3)/∂x = (-sin(2 × 3) + 3 - 2 × cos(2 × 3) × 3) × 4
= -9.92642488681308
26.235323985591407
26.235323985591407
-9.92642488681308
-9.92642488681308
151/172
Other Example
 Emulating C# LINQ in Java
– Language INtegrated Query
152/172
DISCUSSIONS
153/172
Questions
 In Java
– How to best open JVM’s closed world?
– How to best bridge memory models?
154/172
Answers
 In Java
– How to best open JVM’s closed world?
• Panama
• Babylon
– How to best bridge memory models?
• Panama
• Valhalla
155/172
The Isthmus in the JVM
1. Syntax: lambdas vs. function pointers, no C macros, no C++ templates
2. Naming: naming and scoping
3. Data types: Booleans, strings, which always have headers
4. Storage management: many native libraries operate through pointers
to memory, garbage collection
5. Exceptions: C++ and Java exceptions behave differently; C APIs
sometimes require ad hoc polling for errors
6. Semantics: Java strings are immutable while C “strings” are character
arrays, C++ strings are yet different
7. Performance: strings, boxing, copying cause performance “potholes”
8. Safety: the JVM must continue to operate correctly even in the face of
errors or abuse of any single API
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
156/172
The Isthmus in the JVM
1. Syntax: lambdas vs. function pointers, no C
macros, no C++ templates
 With project Panama, possible to manipulate
C pointers
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
157/172
The Isthmus in the JVM
2. Naming: naming and scoping
 Nothing much here…
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
158/172
The Isthmus in the JVM
3. Data types: Booleans, strings, which always
have headers
 With Project Valhalla, possible to create
value classes/objects
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
159/172
The Isthmus in the JVM
4. Storage management: many native libraries
operate through pointers to memory,
garbage collection
 With Project Panama, possible to manipulate
memory from Java
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
160/172
The Isthmus in the JVM
5. Exceptions: C++ and Java exceptions
behave differently; C APIs sometimes
require ad hoc polling for errors
 With Project Babylon, possible to rewrite
code automagically
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
161/172
The Isthmus in the JVM
6. Semantics: Java strings are immutable
while C “strings” are character arrays, C++
strings are yet different
 With Project Babylon, possible to rewrite
code automagically
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
162/172
The Isthmus in the JVM
7. Performance: strings, boxing, copying
cause performance “potholes”
 With Project Valhalla, possible to have
“primitive” performance
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
163/172
The Isthmus in the JVM
8. Safety: the JVM must continue to operate
correctly even in the face of errors or abuse
of any single API
 With Project Panama, more Java code, less
C code, less risks
https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
164/172
Three-prong Approach
https://en.wikipedia.org/wiki/Valhalla
https://www.historyextra.com/period/ancient-history/babylon-babylonia-tower-babel-hanging-gardens-hammurabi/
https://www.georgeglazer.com/wpmain/product/where-atlantic-pacific-meet-the-panama-canal-to-day-birds-eye-view-by-richard-rummell-1914/
165/172
With Such An Approach
166/172
With Such An Approach
final OpenAiChatModel model = OpenAiChatModel.builder().apiKey(Main.API_KEY)
.modelName(OpenAiChatModelName.GPT_4_O_MINI).build();
final String answer = model.chat("Give me the advantages and disadvantages of Java");
System.out.println(answer);
167/172
With Such An Approach
final OpenAiChatModel model = OpenAiChatModel.builder().apiKey(Main.API_KEY)
.modelName(OpenAiChatModelName.GPT_4_O_MINI).build();
final String answer = model.chat("Give me the advantages and disadvantages of Java");
System.out.println(answer);
Java is a widely-used programming language known for its versatility, portability, and robust nature. Here are some
advantages and disadvantages of using Java:
### Advantages of Java
1. **Platform Independence**: Java is designed to be platform-independent at both the source and binary levels, thanks
to the Java Virtual Machine (JVM). This allows developers to write code once and run it anywhere (Write Once, Run
Anywhere - WORA).
[...]
8. **Mature Ecosystem**: Java has a mature ecosystem with enterprise-level solutions, making it a preferred choice for
large-scale applications, including web and mobile development.
### Disadvantages of Java
1. **Performance**: Java can be slower than some compiled languages (such as C or C++) due to the overhead of the JVM
and garbage collection, making it less suitable for performance-critical applications.
[...]
8. **Dependence on JVM**: Java applications require the Java Runtime Environment (JRE) to run, which may not be
available in all environments.
In conclusion, Java is a powerful and versatile language with many advantages, particularly in enterprise and cross-
platform applications. However, developers should consider its disadvantages when selecting a programming language for
specific projects.
168/172
With Such An Approach
 Actually…
https://github.com/langchain4j/langchain4j/blob/main/langchain4j-open-
ai/src/main/java/dev/langchain4j/model/openai/OpenAiChatModel.java
this.client = OpenAiClient.builder()
.httpClientBuilder(builder.httpClientBuilder)
.baseUrl(getOrDefault(builder.baseUrl, DEFAULT_OPENAI_URL))
.apiKey(builder.apiKey)
.organizationId(builder.organizationId)
.projectId(builder.projectId)
.connectTimeout(getOrDefault(builder.timeout, ofSeconds(15)))
.readTimeout(getOrDefault(builder.timeout, ofSeconds(60)))
.logRequests(getOrDefault(builder.logRequests, false))
.logResponses(getOrDefault(builder.logResponses, false))
.userAgent(DEFAULT_USER_AGENT)
.customHeaders(builder.customHeaders)
.build();
169/172
With Such An Approach
 Actually…
https://github.com/langchain4j/langchain4j/blob/main/langchain4j-open-
ai/src/main/java/dev/langchain4j/model/openai/OpenAiChatModel.java
this.client = OpenAiClient.builder()
.httpClientBuilder(builder.httpClientBuilder)
.baseUrl(getOrDefault(builder.baseUrl, DEFAULT_OPENAI_URL))
.apiKey(builder.apiKey)
.organizationId(builder.organizationId)
.projectId(builder.projectId)
.connectTimeout(getOrDefault(builder.timeout, ofSeconds(15)))
.readTimeout(getOrDefault(builder.timeout, ofSeconds(60)))
.logRequests(getOrDefault(builder.logRequests, false))
.logResponses(getOrDefault(builder.logResponses, false))
.userAgent(DEFAULT_USER_AGENT)
.customHeaders(builder.customHeaders)
.build();
It’s a REST call!
170/172
With Such An Approach
 Three ways for language interoperability
– REST APIs and such
– Script engines
– FFIs
 They have different (dis)advantages!
171/172
With Such An Approach
 REST APIs and such
– Simple
– Slow, duplications
 Script engines
– Complex
– Fast, some duplications
 FFIs
– Convoluted
– Fast, no duplications
172/172
With Such An Approach
 REST APIs and such
– Simple
– Slow, duplications
 Script engines
– Complex
– Fast, some duplications
 FFIs
– Convoluted
– Very fast, no duplications
With Projects Panama,
Valhalla, and Babylon!

Projects Panama, Valhalla, and Babylon: Java is the New Python v0.9

  • 1.
    Yann-Gaël Guéhéneuc (/jan/, he/il) Worklicensed under Creative Commons BY-NC-SA 4.0 International Java is the New Python (Or How to Open the World) Version 0.9 25/03/05
  • 2.
    2/172 Any questions/comments arewelcome at yann-gael.gueheneuc@concordia.ca Source code available at https://github.com/ptidejteam/tutorials- JavaIsTheNewPython
  • 3.
    3/172 Inspiration  2025 Isthe Last Year of Python Dominance in AI: Java Comin’ – https://thenewstack.io/2025-is-the-last-year-of- python-dominance-in-ai-java-comin/  The Isthmus in the VM – https://cr.openjdk.org/~jrose/panama/isthmus-in- the-vm-2014.html
  • 4.
    4/172 Observations  Machine learning/ AI has made some great progress in recent years  By coincidence, most libraries are written in C++ or Python
  • 5.
    5/172 Observations C++  Complexity ofthe syntax  Complexity of the semantic  Multiple ways to do the same things  No garbage collector  No memory safety Python  Python is slow at runtime  Cannot do mobile apps  Difficult to use with other languages  High memory consumption  Not used in enterprise development  Runtime errors  Simplicity https://www.geeksforgeeks.org/advantages-and-disadvantages-of-cpp/ https://www.geeksforgeeks.org/disadvantages-of-python/
  • 6.
    6/172 Observations  “However, enterprisesare realizing that Java is the better choice for enterprise-level deployments. We’re likely to see Java outpace Python within the next 18 months to three years.” —Simon Ritter, deputy CTO, Azul Systems, January 2025
  • 7.
    7/172 Observations  “However, enterprisesare realizing that Java is the better choice for enterprise-level deployments. We’re likely to see Java outpace Python within the next 18 months to three years.” —Simon Ritter, deputy CTO, Azul Systems, January 2025 Emphasis mine
  • 8.
    8/172 Questions  In Java –How to best use existing libraries (C++, Python)? – How to best use “new” hardware (GPUs)?
  • 9.
    9/172 Questions  In Java –How to best open JVM’s closed world? – How to best bridge memory models?
  • 10.
  • 11.
  • 12.
    12/172 The Isthmus inthe JVM 1. Syntax: lambdas vs. function pointers, no C macros, no C++ templates 2. Naming: naming and scoping 3. Data types: Booleans, strings, which always have headers 4. Storage management: many native libraries operate through pointers to memory, garbage collection 5. Exceptions: C++ and Java exceptions behave differently; C APIs sometimes require ad hoc polling for errors 6. Semantics: Java strings are immutable while C “strings” are character arrays, C++ strings are yet different 7. Performance: strings, boxing, copying cause performance “potholes” 8. Safety: the JVM must continue to operate correctly even in the face of errors or abuse of any single API https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 13.
    13/172 1. Syntax  Javalambdas  C/C++ function pointers static void methodNeedingSomeComparator( final BiFunction<Integer, Integer, Integer> aComparator) { System.out.println(aComparator.apply(1, 2)); System.out.println(aComparator); } ... final BiFunction<Integer, Integer, Integer> max4 = Math::max; Main.methodNeedingSomeComparator(max4); System.out.println(max4); typedef int (*fp_max_comparator)(const int, const int); void function_needing_some_comparator(const fp_max_comparator comparator) { printf("%dn", compartor(1, 2)); } int my_max_function(const int a, const int b) { ... } ... function_needing_some_comparator(&my_max_function);
  • 14.
    14/172 interface Executable { intmyMax(final int a, final int b); } class MyExecutable implements Executable { public int myMax(final int a, final int b) { return Math.max(a, b); } } final MyExecutable max1 = new MyExecutable(); System.out.println(max1.myMax(1, 2)); class MySecondExecutable implements BiFunction<Integer, Integer, Integer> { public Integer apply(final Integer a, final Integer b) { return Math.max(a, b); } } final MySecondExecutable max2 = new MySecondExecutable(); Syntax.methodNeedingSomeComparator(max2); final BiFunction<Integer, Integer, Integer> max3 = new BiFunction<Integer, Integer, Integer>() { public Integer apply(final Integer a, final Integer b) { return Math.max(a, b); } }; Syntax.methodNeedingSomeComparator(max3); final BiFunction<Integer, Integer, Integer> max4 = (final Integer a, final Integer b) -> { return Math.max(a, b); }; Syntax.methodNeedingSomeComparator(max4); final BiFunction<Integer, Integer, Integer> max5 = Math::max; Syntax.methodNeedingSomeComparator(max5);
  • 15.
    15/172 interface Executable { intmyMax(final int a, final int b); } class MyExecutable implements Executable { public int myMax(final int a, final int b) { return Math.max(a, b); } } final MyExecutable max1 = new MyExecutable(); System.out.println(max1.myMax(1, 2)); class MySecondExecutable implements BiFunction<Integer, Integer, Integer> { public Integer apply(final Integer a, final Integer b) { return Math.max(a, b); } } final MySecondExecutable max2 = new MySecondExecutable(); Syntax.methodNeedingSomeComparator(max2); final BiFunction<Integer, Integer, Integer> max3 = new BiFunction<Integer, Integer, Integer>() { public Integer apply(final Integer a, final Integer b) { return Math.max(a, b); } }; Syntax.methodNeedingSomeComparator(max3); final BiFunction<Integer, Integer, Integer> max4 = (final Integer a, final Integer b) -> { return Math.max(a, b); }; Syntax.methodNeedingSomeComparator(max4); final BiFunction<Integer, Integer, Integer> max5 = Math::max; Syntax.methodNeedingSomeComparator(max5); Can’t be used by the method needing it…
  • 16.
    16/172 1. Syntax  Outputsand object types 2 net.ptidej.isthmus.Syntax$1MyExecutable@372f7a8d 2 net.ptidej.isthmus.Syntax$1MySecondExecutable@28a418fc 2 net.ptidej.isthmus.Syntax$1@1f32e575 2 net.ptidej.isthmus.Syntax$$Lambda/0x0000028e58001240@77459877 2 net.ptidej.isthmus.Syntax$$Lambda/0x0000028e58001470@33c7353a
  • 17.
    17/172 2. Naming Java  Separation C++ No separation public class Naming { public int identifier = 0; public int identifier() { return 0; } } class Naming { public: int identifier = 0; void identifier() { } }; error: 'void Naming::identifier()' conflicts with a previous declaration
  • 18.
    18/172 2. Naming Java  Nonesting  Impact on visibility C++  Nesting  No impact on visibility package a.b; public class X { } package b; public class X { } public static void main(String[] args) { System.out.println(a.b.X.class); System.out.println(b.X.class); } namespace a { namespace b { int x = 0; } } namespace b { string x; } using namespace a; void foo() { b::x = 42; } error: reference to 'b' is ambiguous
  • 19.
    19/172 2. Naming Java  Modules C++ No equivalent – Maybe linker libs? module isthmus.java { requires java.logging; } package net.ptidej.isthmus; import java.util.logging.Logger; public class Main { private static Logger java. Logging = Logger.getLogger("net.ptidej.isthmus"); public static void main(final String[] args) { Main.logger.fine("Hello, World!"); } }
  • 20.
    20/172 3. Data types Java Booleans are their own  Strings are immutable C/C++  Booleans are shorts  Strings are mutable bool a[5]; bool result; for (int i = 0; i < 5; i++) { cout << a[i] << " "; result += a[i]; } cout << endl << result << endl; boolean a[] = new boolean[5]; for (int i = 0; i < 5; i++) { System.out.println(a[i]); } string string1 = "Hello"; string string2 = ", World!"; string string3 = string1 + string2; cout << string3 << endl; string3[0] = 'Y'; cout << string3 << endl; final String string1 = "Hello"; final String string2 = ", World!"; final String string3 = string1 + string2; System.out.println(string3); final StringBuilder string4 = new StringBuilder(string3); string4.setCharAt(0, 'Y'); System.out.println(string4);
  • 21.
    21/172 3. Data types Java Performance  Generics – Autoboxing C/C++  Performance  Consistency public interface IntFunction<R> public interface ToIntFunction<T> vs. Predicate<int, int> using namespace std; void abssort(float *x, unsigned n) { sort(x, x + n, [](float a, float b) { return (abs(a) < abs(b)); }); }
  • 22.
    22/172 3. Data types Java Primitive types  Objects and references C/C++  Primitive types  Pointers https://stackoverflow.com/questions/373419/whats-the-difference-between- passing-by-reference-vs-passing-by-value
  • 23.
    23/172 4. Storage management Java Objects  Garbage collection C/C++  Pointers  Memory lifetime https://www.baeldung.com/java-stack-heap https://study.com/academy/lesson/program-memory-in-c-programming.html vs.
  • 24.
    24/172 5. Exceptions Java  NullPointerException Exceptions are objects and thrown consistently C/C++  null values – One of the purpose of Rust!  Some errors must be polled actively int example_errno() { const char *filename = "somefile.txt"; ifstream file(filename); if (!file) { switch (errno) { case ENOENT: cerr << "Error: File doesn't exist." << endl; break; ... default: cerr << "Error: Cannot open file." << endl; break; } return 1; // Some error happened } ...
  • 25.
    25/172 6. Semantics  Classesvs. interfaces  Package-only visibility – Modules – Sealing  final vs. const  Single vs. multiple-inheritance – Virtual vs. non-virtual member functions  … https://www.cs.gordon.edu/courses/cs212/paperwork/Java-C++comparison.pdf
  • 26.
    26/172 7. Performance  “Codewhich uses Java primitives performs on a par corresponding C code, but…”  https://unriskinsight.blogspot.com/2014/06/fa st-functional-goats-lions-and-wolves.html https://www.oracle.com/java/technologies/performance-comparisons.html
  • 27.
    27/172 7. Performance  “Codewhich uses Java primitives performs on a par corresponding C code, but…”  https://unriskinsight.blogspot.com/2014/06/fa st-functional-goats-lions-and-wolves.html Many threats to validity! https://www.oracle.com/java/technologies/performance-comparisons.html
  • 28.
    28/172 8. Safety  Noattacks from untrusted code  No privilege escalation from untrusted code  No crashes  No leaks  No hangs  Rare outages  No unguarded casts
  • 29.
    29/172 8. Safety  Noattacks from untrusted code  No privilege escalation from untrusted code  No crashes  No leaks  No hangs  Rare outages  No unguarded casts See later…
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
    35/172 Three-prong Approach  ProjectPanama FFI  Project Valhalla value class/objects  Project Babylon code reflection
  • 36.
  • 37.
    37/172 Foreign Function Interface Early access build from Project Valhalla – https://jdk.java.net/jextract/ – JDK 22 + JExtract v6.47 (24/10/09)
  • 38.
    38/172 Java Native Interface Write Java code with native methods – And System.loadLibrary()  Generate header file with javah – javac -h since Java 10  Implement the header file  Compile the Java code – Can be done earlier too  Run the compile code
  • 39.
    39/172 Java Native Interface packagenet.ptidej.panama.jni; public class Main { static { System.loadLibrary("net_ptidej_panama_jni_Main"); } public static native int stringLength(final String s); public static void main(final String[] args) { final String s = "Hello, world!"; System.out.println(Main.stringLength(s)); } } /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class net_ptidej_panama_jni_Main */ #ifndef _Included_net_ptidej_panama_jni_Main #define _Included_net_ptidej_panama_jni_Main #ifdef __cplusplus extern "C" { #endif /* * Class: net_ptidej_panama_jni_Main * Method: stringLength * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif #include <cstring> #include "net_ptidej_panama_jni_Main.h" JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *env, jclass jc, jstring js) { const char* s = env->GetStringUTFChars(js, NULL); return strlen(s); }
  • 40.
    40/172 Java Native Interface packagenet.ptidej.panama.jni; public class Main { static { System.loadLibrary("net_ptidej_panama_jni_Main"); } public static native int stringLength(final String s); public static void main(final String[] args) { final String s = "Hello, world!"; System.out.println(Main.stringLength(s)); } } /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class net_ptidej_panama_jni_Main */ #ifndef _Included_net_ptidej_panama_jni_Main #define _Included_net_ptidej_panama_jni_Main #ifdef __cplusplus extern "C" { #endif /* * Class: net_ptidej_panama_jni_Main * Method: stringLength * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif #include <cstring> #include "net_ptidej_panama_jni_Main.h" JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *env, jclass jc, jstring js) { const char* s = env->GetStringUTFChars(js, NULL); return strlen(s); } Opens a door in the JVM
  • 41.
    41/172 Java Native Interface packagenet.ptidej.panama.jni; public class Main { static { System.loadLibrary("net_ptidej_panama_jni_Main"); } public static native int stringLength(final String s); public static void main(final String[] args) { final String s = "Hello, world!"; System.out.println(Main.stringLength(s)); } } /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class net_ptidej_panama_jni_Main */ #ifndef _Included_net_ptidej_panama_jni_Main #define _Included_net_ptidej_panama_jni_Main #ifdef __cplusplus extern "C" { #endif /* * Class: net_ptidej_panama_jni_Main * Method: stringLength * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif #include <cstring> #include "net_ptidej_panama_jni_Main.h" JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *env, jclass jc, jstring js) { const char* s = env->GetStringUTFChars(js, NULL); return strlen(s); } Opens a door in the JVM JVM jargon
  • 42.
    42/172 Java Native Interface packagenet.ptidej.panama.jni; public class Main { static { System.loadLibrary("net_ptidej_panama_jni_Main"); } public static native int stringLength(final String s); public static void main(final String[] args) { final String s = "Hello, world!"; System.out.println(Main.stringLength(s)); } } /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class net_ptidej_panama_jni_Main */ #ifndef _Included_net_ptidej_panama_jni_Main #define _Included_net_ptidej_panama_jni_Main #ifdef __cplusplus extern "C" { #endif /* * Class: net_ptidej_panama_jni_Main * Method: stringLength * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif #include <cstring> #include "net_ptidej_panama_jni_Main.h" JNIEXPORT jint JNICALL Java_net_ptidej_panama_jni_Main_stringLength (JNIEnv *env, jclass jc, jstring js) { const char* s = env->GetStringUTFChars(js, NULL); return strlen(s); } Opens a door in the JVM JVM jargon JVM C API
  • 43.
    43/172 Java Native Interface gcc -Wl,--add-stdcall-alias -shared -I"${JAVA_HOME}"/include -I"${JAVA_HOME}"/include/win32 -o net_ptidej_panama_jni_Main.dll net_ptidej_panama_jni_Main.cpp  java net.ptidej.panama.jni.Main – Prints 13
  • 44.
    44/172 Java Native Interface Possible bug in the JVM – “JVM Segmentation Fault with Single-file Source-code Program and JNI” • java Main.class will throw (correctly) java.lang.UnsatisfiedLinkError • java Main.java will also throw (correctly) java.lang.UnsatisfiedLinkError • But delete Main.class and java Main.java either throws (correctly) java.lang.UnsatisfiedLinkError or writes Segmentation fault without further info. or freezes and must be killed https://easydrawingguides.com/how-to-draw-a-ladybug-really-easy-drawing-tutorial/
  • 45.
    45/172 Java Native Interface Limitations – Sits between the two “worlds” • Some code in Java, some code in C/C++ – Needs marshalling/mapping of data types – Requires careful idioms – Could crash the JVM • Cf. possible Segmentation fault – Lots of boiler-plate code
  • 46.
    46/172 java.lang.foreign.Linker  Focus onmemory  Increase amount of Java code  Remove all C boiler-plate code
  • 47.
    47/172 java.lang.foreign.Linker public class Main{ public static void main(final String[] args) throws Throwable { final Linker linker = Linker.nativeLinker(); final SymbolLookup dll = SymbolLookup.libraryLookup( "net_ptidej_panama_version2_Main.dll", Arena.global()); final MethodHandle strlen = linker.downcallHandle( dll.find("stringLength").orElseThrow(), FunctionDescriptor.of( ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (final Arena arena = Arena.ofConfined()) { final MemorySegment cString = arena.allocateFrom("Hello, World!"); final long length = (long) strlen.invoke(cString); System.out.println(length); } } } #include <cstring> #include "net_ptidej_panama_version2_Main.h" long stringLength(const char *s) { return strlen(s); }
  • 48.
    48/172 java.lang.foreign.Linker public class Main{ public static void main(final String[] args) throws Throwable { final Linker linker = Linker.nativeLinker(); final SymbolLookup dll = SymbolLookup.libraryLookup( "net_ptidej_panama_version2_Main.dll", Arena.global()); final MethodHandle strlen = linker.downcallHandle( dll.find("stringLength").orElseThrow(), FunctionDescriptor.of( ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (final Arena arena = Arena.ofConfined()) { final MemorySegment cString = arena.allocateFrom("Hello, World!"); final long length = (long) strlen.invoke(cString); System.out.println(length); } } } #include <cstring> #include "net_ptidej_panama_version2_Main.h" long stringLength(const char *s) { return strlen(s); } Much simpler and “natural” C code
  • 49.
    49/172 java.lang.foreign.Linker  Linker – nativeLinker() SymbolLookup – libraryLookup()  MethodHandle – invoke()  Arena – global() – ofConfined()  MemorySegment – allocateFrom()  ABI (Application Binary Interface) – Linker for the ABI of the native platform  A symbol is a named entity – Loads a library, creates a lookup  A typed, executable entity – Invokes the method handle  Controls the life of native memory – Program-long, thread-friendly, zeroed – Temporary, zeroed  A contiguous region of memory – New memory segment initialised with the provided, converted value
  • 50.
    50/172 java.lang.foreign.Linker  Advantages – Simpler,natural C code – More Java code  Limitations – Must handle manually the foreign library
  • 51.
    51/172 java.lang.foreign.Linker public class Main{ public static void main(final String[] args) throws Throwable { final Linker linker = Linker.nativeLinker(); final SymbolLookup stringh = linker.defaultLookup(); final MethodHandle strlen = linker.downcallHandle( stringh.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (final Arena arena = Arena.ofConfined()) { final MemorySegment cString = arena.allocateFrom("Hello, World!"); final long length = (long) strlen.invokeExact(cString); System.out.println(length); } } }
  • 52.
    52/172 java.lang.foreign.Linker public class Main{ public static void main(final String[] args) throws Throwable { final Linker linker = Linker.nativeLinker(); final SymbolLookup stringh = linker.defaultLookup(); final MethodHandle strlen = linker.downcallHandle( stringh.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (final Arena arena = Arena.ofConfined()) { final MemorySegment cString = arena.allocateFrom("Hello, World!"); final long length = (long) strlen.invokeExact(cString); System.out.println(length); } } } Default lookup
  • 53.
    53/172 java.lang.foreign.Linker public class Main{ public static void main(final String[] args) throws Throwable { final Linker linker = Linker.nativeLinker(); final SymbolLookup stringh = linker.defaultLookup(); final MethodHandle strlen = linker.downcallHandle( stringh.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (final Arena arena = Arena.ofConfined()) { final MemorySegment cString = arena.allocateFrom("Hello, World!"); final long length = (long) strlen.invokeExact(cString); System.out.println(length); } } } Default lookup For a known C function
  • 54.
    54/172 java.lang.foreign.Linker  Advantages – Simpler,natural C code – Less Java code  Limitations – Boiler-plate Java code
  • 55.
  • 56.
    56/172 Value Classes andObjects  Early access build from Project Valhalla – https://jdk.java.net/valhalla/ – (Partial) JDK 23 + Valhalla
  • 57.
  • 58.
    58/172 Java Split Personalities Everything is an Object  
  • 59.
    59/172 Java Split Personalities Everything is an Object  Except for primitive types – Eight of them: boolean, byte, char, short, int, long, float, double 
  • 60.
    60/172 Java Split Personalities Everything is an Object  Except for primitive types – Eight of them: boolean, byte, char, short, int, long, float, double  Except for arrays – Class of Object[] is [Ljava.lang.Object;
  • 61.
    61/172 Java Split Personalities Everything is an Object  Except for primitive types – Eight of them: boolean, byte, char, short, int, long, float, double  Except for arrays – Class of Object[] is [Ljava.lang.Object;
  • 62.
    62/172 Performance Costs  Theseexceptions were a good idea – In 1995 • Memory fetch ≈ Computation like addition  But circumstances have changed – In 2025 • Cache miss ≈ 1,000 × computation like addition • Significant different relative cost
  • 63.
    63/172  Heap allocation –Memory indirections – Need flat (cache-efficient) and dense (memory-efficient) data representation  By-reference parameters – Pointer dereferencing – Need flat(ter) calling convention to pass components by values Performance Costs
  • 64.
    64/172 Development Costs  Generics –Simpler, consistent APIs – Primitive types wrinkles  Autoboxing – Loose identity, gain random identity – Irregularity and cost – Gotchas public interface IntFunction<R> public interface ToIntFunction<T> vs. Predicate<int, int>
  • 65.
    65/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 66.
    66/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); } NullPointerException
  • 67.
    67/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 68.
    68/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); } Never null (even if missing)
  • 69.
    69/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 70.
    70/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); } Prints i = 1 d = 2.0 o1 = 1 o2 = 1.0 false
  • 71.
    71/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 72.
    72/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); } Prints 1. 2. 3.
  • 73.
    73/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 74.
    74/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); } The method f(Object, boolean) is ambiguous
  • 75.
    75/172 (Gotchas) try { final Integera = null; System.out.println("a = " + a); final int b = a; System.out.println("b = " + b); } catch (final NullPointerException e) { } { final ResultSet rs = this.doSomeDatabaseQuery(); final Double value = rs.getDouble("someDoubleField"); } { final Integer i = new Integer(1); final Double d = new Double(2.0); System.out.println("i = " + i); System.out.println("d = " + d); final Object o1 = i; System.out.println("o1 = " + o1); final Object o2 = true ? i : d; System.out.println("o2 = " + o2); System.out.println(o1.equals(o2)); } { final int smallNumberInt = 42; if (smallNumberInt == 42) System.out.println("1."); final Integer smallNumberInteger = Integer.valueOf(42); if (smallNumberInteger == (Object) 42) System.out.println("2."); final int largeNumberInt = 500; if (largeNumberInt == 500) System.out.println("3."); final Integer largeNumberInteger = Integer.valueOf(500); if (largeNumberInteger == (Object) 500) System.out.println("4."); } { final int value = 42; final Vector v = new Vector(); v.add(value); System.out.println("first = " + v.getFirst().getClass()); Main.f(value, false); } private static void f(final Object a, final boolean b) { System.out.println("f(Object a, boolean b)"); } private static void f(final Object a, final Object b) { System.out.println("f(Object a, Object b)"); }
  • 76.
    76/172 Root Cause  Identity –All instances (and all classes) are uniquely identified
  • 77.
    77/172 Root Cause  Identity –All instances (and all classes) are uniquely identified final int i1 = 42; final int j1 = 42; System.out.println(i1 == j1); final Integer i2 = Integer.valueOf(42); final Integer j2 = Integer.valueOf("42"); System.out.println(i2 == j2); System.out.println(System.identityHashCode(i2)); System.out.println(System.identityHashCode(j2)); final String s1 = "Hello, World!"; final String s2 = "Hello, Wordl!"; System.out.println(s1 == s2); final ClassLoader cl1 = Main.class.getClassLoader(); final Class<?> c1 = cl1.loadClass("net.....Main"); final ClassLoader cl2 = Main.class.getClassLoader(); final Class<?> c2 = cl2.loadClass("net.....Main"); final MyClassLoader cl3 = new MyClassLoader(); final Class<?> c3 = cl3.findClass("net.....Main"); System.out.println(c1 == c2); System.out.println(c1 == c3);
  • 78.
    78/172 Root Cause  Identity –All instances (and all classes) are uniquely identified final int i1 = 42; final int j1 = 42; System.out.println(i1 == j1); final Integer i2 = Integer.valueOf(42); final Integer j2 = Integer.valueOf("42"); System.out.println(i2 == j2); System.out.println(System.identityHashCode(i2)); System.out.println(System.identityHashCode(j2)); final String s1 = "Hello, World!"; final String s2 = "Hello, Wordl!"; System.out.println(s1 == s2); final ClassLoader cl1 = Main.class.getClassLoader(); final Class<?> c1 = cl1.loadClass("net.....Main"); final ClassLoader cl2 = Main.class.getClassLoader(); final Class<?> c2 = cl2.loadClass("net.....Main"); final MyClassLoader cl3 = new MyClassLoader(); final Class<?> c3 = cl3.findClass("net.....Main"); System.out.println(c1 == c2); System.out.println(c1 == c3); true true 617901222 617901222 false true false
  • 79.
    79/172 Solution  Identity-less instances –Value classes – Value objects “Codes like a class, works like an int.”
  • 80.
    80/172 Value Classes public valueclass Substring implements CharSequence { private String str; private int start; private int end; public Substring(final String str, final int start, final int end) { Substring.checkBounds(start, end, str.length()); this.str = str; this.start = start; this.end = end; } public int length() { return this.end - this.start; } public char charAt(final int i) { Substring.checkBounds(0, i, length()); return str.charAt(start + i); } public Substring subSequence(final int s, final int e) { Substring.checkBounds(s, e, length()); return new Substring(str, start + s, start + e); } public String toString() { return str.substring(start, end); } private static void checkBounds(final int start, final int end, final int length) { if (start < 0 || end < start || length < end) { throw new IndexOutOfBoundsException(); } } }
  • 81.
    81/172 Value Classes public valueclass Substring implements CharSequence { private String str; private int start; private int end; public Substring(final String str, final int start, final int end) { Substring.checkBounds(start, end, str.length()); this.str = str; this.start = start; this.end = end; } public int length() { return this.end - this.start; } public char charAt(final int i) { Substring.checkBounds(0, i, length()); return str.charAt(start + i); } public Substring subSequence(final int s, final int e) { Substring.checkBounds(s, e, length()); return new Substring(str, start + s, start + e); } public String toString() { return str.substring(start, end); } private static void checkBounds(final int start, final int end, final int length) { if (start < 0 || end < start || length < end) { throw new IndexOutOfBoundsException(); } } } New keyword
  • 82.
    82/172 Value Classes public valueclass Substring implements CharSequence { private String str; private int start; private int end; public Substring(final String str, final int start, final int end) { Substring.checkBounds(start, end, str.length()); this.str = str; this.start = start; this.end = end; } public int length() { return this.end - this.start; } public char charAt(final int i) { Substring.checkBounds(0, i, length()); return str.charAt(start + i); } public Substring subSequence(final int s, final int e) { Substring.checkBounds(s, e, length()); return new Substring(str, start + s, start + e); } public String toString() { return str.substring(start, end); } private static void checkBounds(final int start, final int end, final int length) { if (start < 0 || end < start || length < end) { throw new IndexOutOfBoundsException(); } } }
  • 83.
    83/172 Value Classes public valueclass Substring implements CharSequence { private String str; private int start; private int end; public Substring(final String str, final int start, final int end) { Substring.checkBounds(start, end, str.length()); this.str = str; this.start = start; this.end = end; } public int length() { return this.end - this.start; } public char charAt(final int i) { Substring.checkBounds(0, i, length()); return str.charAt(start + i); } public Substring subSequence(final int s, final int e) { Substring.checkBounds(s, e, length()); return new Substring(str, start + s, start + e); } public String toString() { return str.substring(start, end); } private static void checkBounds(final int start, final int end, final int length) { if (start < 0 || end < start || length < end) { throw new IndexOutOfBoundsException(); } } } Method call before super()
  • 84.
    84/172 Value Classes public valueclass Substring implements CharSequence { private String str; private int start; private int end; public Substring(final String str, final int start, final int end) { Substring.checkBounds(start, end, str.length()); this.str = str; this.start = start; this.end = end; } public int length() { return this.end - this.start; } public char charAt(final int i) { Substring.checkBounds(0, i, length()); return str.charAt(start + i); } public Substring subSequence(final int s, final int e) { Substring.checkBounds(s, e, length()); return new Substring(str, start + s, start + e); } public String toString() { return str.substring(start, end); } private static void checkBounds(final int start, final int end, final int length) { if (start < 0 || end < start || length < end) { throw new IndexOutOfBoundsException(); } } }
  • 85.
    85/172 Value Classes  Cannotcompile with Eclipse – Or any other current IDEs? $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/Substring.java netptidejvalhallavalueclassSubstring.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value class Substring implements CharSequence { ^ netptidejvalhallavalueclassSubstring.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value class Substring implements CharSequence { ^ netptidejvalhallavalueclassSubstring.java:8: warning: [preview] statements before super() is a preview feature and may be removed in a future release. public Substring(final String str, final int start, final int end) { ^ 3 warnings
  • 86.
    86/172 Value Classes  Theclass is implicitly final […]  All instance fields are implicitly final […]  The class does not extend an identity class or an identity interface  All constructors are implicitly regulated, […], limiting use of this […]  No instance methods are […] synchronised  (Possibly) The class does not declare a finalize() method
  • 87.
    87/172 Value Classes public staticvoid main(final String[] args) { final Substring subs1 = new Substring("Hello, World!", 7, 13); System.out.println(subs1); final Substring subs2 = new Substring("Hello, World!", 7, 13); System.out.println(subs1); System.out.println(Modifier.isIdentity(Substring.class.getModifiers())); System.out.println(subs1 == subs2); }
  • 88.
    88/172 Value Classes World! World! false true public staticvoid main(final String[] args) { final Substring subs1 = new Substring("Hello, World!", 7, 13); System.out.println(subs1); final Substring subs2 = new Substring("Hello, World!", 7, 13); System.out.println(subs1); System.out.println(Modifier.isIdentity(Substring.class.getModifiers())); System.out.println(subs1 == subs2); }
  • 89.
    89/172 Value and Identity publicidentity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); }
  • 90.
    90/172 Value and Identity publicidentity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); } $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected public identity interface ICounter { ^ 1 error $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface public value interface IJSONValue { ^ 1 error 2 warnings
  • 91.
    91/172 Value and Identity publicidentity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); } $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected public identity interface ICounter { ^ 1 error $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface public value interface IJSONValue { ^ 1 error 2 warnings
  • 92.
    92/172 Value and Identity publicidentity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); } $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/ICounter.java netptidejvalhallavalueclassICounter.java:3: error: class, interface, enum, or record expected public identity interface ICounter { ^ 1 error $ javac --enable-preview -source 23 -Xlint:preview -d ../bin/ net/ptidej/valhalla/valueclass/IJSONValue.java netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: warning: [preview] value classes are a preview feature and may be removed in a future release. public value interface IJSONValue { ^ netptidejvalhallavalueclassIJSONValue.java:3: error: illegal combination of modifiers: value and interface public value interface IJSONValue { ^ 1 error 2 warnings Not yet implemented
  • 93.
    93/172 Value and Identity By default, an interface may be implemented by both value classes and identity classes  [If an] interface is only meant for one kind of class or the other  “It is an error for a value class or interface to extend an identity class or interface […]” public identity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); }
  • 94.
    94/172 Value and Identity By default, an interface may be implemented by both value classes and identity classes  [If an] interface is only meant for one kind of class or the other  “It is an error for a value class or interface to extend an identity class or interface […]” public identity interface ICounter { int getValue(); void increment(); } public value interface IJSONValue { String toJsonString(); } New keywords
  • 95.
    95/172 Value and Identity Special considerations – A functional interface, compatible with lambda expressions, must allow for both value and identity implementations – An abstract class must allow for both value classes and identity classes by default – The class Object is special • A concrete class • Not an identity class • Supports both identity and value subclasses
  • 96.
    96/172 Regulated Constructors  Compilererror – Reading an instance field of the class – Invoking an instance method of the class – Using this, except in an assignment – Using super to access a field or method – Instantiating an inner class with this as enclosing instance – Calling explicitly a non-regulated constructor (super() or this())
  • 97.
    97/172 Regulated Constructors  Compilererror – Reading an instance field of the class – Invoking an instance method of the class – Using this, except in an assignment – Using super to access a field or method – Instantiating an inner class with this as enclosing instance – Calling explicitly a non-regulated constructor (super() or this()) Weaker than the pre- construction context, itself weaker than the static context
  • 98.
    98/172 Constructor Contexts  Static –“The purpose of a static context is to demarcate code that must not refer explicitly or implicitly to the current instance of the class whose declaration lexically encloses the static context. for which there is no current instance defined of the class whose declaration lexically encloses the static context.”  Pre-construction – “Unlike in a static context, an expression in a pre-construction context is free, for example, to refer to the type of the instance under construction.”  Regulated – “[A] constructor must not make any use of this in its body, except to write to an instance field.” https://docs.oracle.com/en/java/javase/22/docs/specs/statements-before-super-jls.html https://openjdk.org/jeps/8277163
  • 99.
    99/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } }
  • 100.
    100/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } } Static
  • 101.
    101/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } } Static Pre-construction
  • 102.
    102/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } } Static Pre-construction Regulated
  • 103.
    103/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } } final B b = new B(42); System.out.println(b); Static Pre-construction Regulated
  • 104.
    104/172 Constructor Contexts class A{ } class B extends A { private String s; private int i; static { System.out.println("Loading of B..."); } { System.out.println("Building of a B..."); this.s = "Omega"; } B(final int a) { System.out.println(a); this.s = "Alpha"; super(); this.i = a; } @Override public String toString() { return this.s + " " + this.i; } } final B b = new B(42); System.out.println(b); Loading of B... 42 Building of a B... Omega 42 Static Pre-construction Regulated
  • 105.
    105/172 Constructor Contexts  Mustenable preview features of Java – javac --enable-preview -source 23 -cp ../bin/ -d ../bin/ net/ptidej/isthmus/constructor/contexts/* – java --enable-preview net.ptidej.isthmus.constructor.contexts. Main
  • 106.
    106/172 Caveats  The ==operator may treat two instances as the same, where previously they were considered different  Attempts to synchronize on an instance will fail, either at compile time or run time  The results of toString(), equals(), and hashCode(), if not overridden, may change  Assumptions about unique ownership of an instance may be violated (e.g., an identical instance may be created at two different times)  Performance will generally improve, but may have surprising different characteristics
  • 107.
  • 108.
    108/172  Thanks to PaulSandoz Juan Fumero For their code and their help
  • 109.
    109/172 Foreign Programming Models SQL  GPUs  Machine learning models  Differentiable programming  …
  • 110.
    110/172 Example f(x, y) =x × (-sin(x × y) + y) × 4  
  • 111.
    111/172 Example f(x, y) =x × (-sin(x × y) + y) × 4 ∂f(x, y)/∂x = (-sin(x × y) + y - x × cos(x × y) × y) × 4
  • 112.
  • 113.
  • 114.
    114/172 Requirements  Model ofJava code  API to manipulate such model 
  • 115.
    115/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model
  • 116.
    116/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model 
  • 117.
    117/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model = Code Reflection
  • 118.
    118/172 Enabling Code Reflection As of today – Don’t even try on Windows • Even with CygWin… – Ubuntu 24.04.2 LTS x86_64 > sudo apt-get install autoconf libasound2-dev libcups2-dev libfontconfig1-dev libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev libxt-dev > sudo apt-get install sdkman > sdk install java 23-open > sdk use java 23-open > git clone https://github.com/openjdk/babylon.git > bash configure --with-boot-jdk=${JAVA_HOME} > make images > export JAVA_HOME=$ROOT_BABYLON/babylon/build/linux-x86_64-server-release/jdk > export PATH=$JAVA_HOME/bin:$PATH https://jjfumero.github.io/posts/2025/02/07/babylon-and-tornadovm
  • 119.
    119/172 Enabling Code Reflection New javac/java versions > java -version openjdk version "24-internal" 2025-03-18 OpenJDK Runtime Environment (build 24-internal-adhoc.guehenyg.babylon) OpenJDK 64-bit Server VN (build 24-internal-adhoc.guehenyg.babylon, mixed mode)
  • 120.
    120/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model
  • 121.
  • 122.
    122/172 Code Model @CodeReflection public staticdouble sub(final double a, final double b) { return a - b; } final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); System.out.println(subMethod); final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get(); System.out.println(funcOp.toText()); funcOp.traverse(null, (acc, codeElement) -> { int depth = 0; CodeElement<?, ?> parent = codeElement; while ((parent = parent.parent()) != null) { depth++; } System.out.println(" ".repeat(depth) + codeElement.getClass()); return acc; });
  • 123.
    123/172 Code Model @CodeReflection public staticdouble sub(final double a, final double b) { return a - b; } class jdk.incubator.code.op.CoreOp$FuncOp class jdk.incubator.code.Body class jdk.incubator.code.Block class jdk.incubator.code.op.CoreOp$VarOp class jdk.incubator.code.op.CoreOp$VarOp class jdk.incubator.code.op.CoreOp$VarAccessOp$VarLoadOp class jdk.incubator.code.op.CoreOp$VarAccessOp$VarLoadOp class jdk.incubator.code.op.CoreOp$SubOp class jdk.incubator.code.op.CoreOp$ReturnOp
  • 124.
    124/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model
  • 125.
    125/172 API for CodeModels  Code models only exist for method annotated with @CodeReflection @CodeReflection public static double sub(final double a, final double b) { return a - b; }
  • 126.
    126/172 API for CodeModels Without @CodeReflection  Size: 2,633 bytes With @CodeReflection  Size: 3,437 bytes public static double sub(double, double); descriptor: (DD)D flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=4, args_size=2 0: dload_0 1: dload_2 2: dsub 3: dreturn LineNumberTable: line 35: 0 public static double sub(double, double); descriptor: (DD)D flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=4, args_size=2 0: dload_0 1: dload_2 2: dsub 3: dreturn LineNumberTable: line 35: 0 RuntimeVisibleAnnotations: 0: #109() jdk.incubator.code.CodeReflection
  • 127.
    127/172 API for CodeModels Without @CodeReflection  Size: 2,633 bytes With @CodeReflection  Size: 3,437 bytes public static double sub(double, double); descriptor: (DD)D flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=4, args_size=2 0: dload_0 1: dload_2 2: dsub 3: dreturn LineNumberTable: line 35: 0 public static double sub(double, double); descriptor: (DD)D flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=4, args_size=2 0: dload_0 1: dload_2 2: dsub 3: dreturn LineNumberTable: line 35: 0 RuntimeVisibleAnnotations: 0: #109() jdk.incubator.code.CodeReflection
  • 128.
    128/172 API for CodeModels With @CodeReflection  Size: 3,437 bytes public static jdk.incubator.code.op.CoreOp$FuncOp op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double(); descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp; flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=0, args_size=0 0: ldc #1 // String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double -> {n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1 @"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double = var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6 @loc="35:3";n}; 2: invokestatic #3 // Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp: (Ljava/lang/String;)Ljdk/incubator/code/Op; 5: checkcast #9 // class jdk/incubator/code/op/CoreOp$FuncOp 8: areturn LineNumberTable: line 1: 0
  • 129.
    129/172 API for CodeModels With @CodeReflection  Size: 3,437 bytes public static jdk.incubator.code.op.CoreOp$FuncOp op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double(); descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp; flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=0, args_size=0 0: ldc #1 // String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double -> {n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1 @"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double = var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6 @loc="35:3";n}; 2: invokestatic #3 // Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp: (Ljava/lang/String;)Ljdk/incubator/code/Op; 5: checkcast #9 // class jdk/incubator/code/op/CoreOp$FuncOp 8: areturn LineNumberTable: line 1: 0
  • 130.
    130/172 API for CodeModels With @CodeReflection  Size: 3,437 bytes public static jdk.incubator.code.op.CoreOp$FuncOp op$net$ptidej$babylon$a$traversal$Main::sub(double, double)double(); descriptor: ()Ljdk/incubator/code/op/CoreOp$FuncOp; flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=0, args_size=0 0: ldc #1 // String func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double -> {n %2 : Var<double> = var %0 @"a" @loc="33:2";n %3 : Var<double> = var %1 @"b" @loc="33:2";n %4 : double = var.load %2 @loc="35:10";n %5 : double = var.load %3 @loc="35:14";n %6 : double = sub %4 %5 @loc="35:10";n return %6 @loc="35:3";n}; 2: invokestatic #3 // Method jdk/incubator/code/parser/OpParser.fromStringOfFuncOp: (Ljava/lang/String;)Ljdk/incubator/code/Op; 5: checkcast #9 // class jdk/incubator/code/op/CoreOp$FuncOp 8: areturn LineNumberTable: line 1: 0 Parser of textually- serialised code models
  • 131.
    131/172 API for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); System.out.println(subMethod); final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get(); System.out.println(funcOp.toText()); funcOp.traverse(null, (acc, codeElement) -> { int depth = 0; CodeElement<?, ?> parent = codeElement; while ((parent = parent.parent()) != null) { depth++; } System.out.println(" ".repeat(depth) + codeElement.getClass()); return acc; }); @CodeReflection public static double sub(final double a, final double b) { return a - b; }
  • 132.
    132/172 final Method subMethod= Main.class.getDeclaredMethod("sub", double.class, double.class); System.out.println(subMethod); final CoreOp.FuncOp funcOp = Op.ofMethod(subMethod).get(); System.out.println(funcOp.toText()); funcOp.traverse(null, (acc, codeElement) -> { int depth = 0; CodeElement<?, ?> parent = codeElement; while ((parent = parent.parent()) != null) { depth++; } System.out.println(" ".repeat(depth) + codeElement.getClass()); return acc; }); @CodeReflection public static double sub(final double a, final double b) { return a - b; } public static double net.ptidej.babylon.a.traversal.Main.sub(double,double) func @"sub" @loc="33:2:[...]/Main.java" (%0 : double, %1 : double)double -> { %2 : Var<double> = var %0 @"a" @loc="33:2"; %3 : Var<double> = var %1 @"b" @loc="33:2"; %4 : double = var.load %2 @loc="35:10"; %5 : double = var.load %3 @loc="35:14"; %6 : double = sub %4 %5 @loc="35:10"; return %6 @loc="35:3"; };
  • 133.
    133/172 Requirements  Model ofJava code  API to manipulate such model  Interpreter to evaluate such model
  • 134.
    134/172 Interpreter for CodeModels package jdk.incubator.code.interpreter; public final class Interpreter { private Interpreter() { } /** * Invokes an invokable operation by interpreting the code elements within the * operations body. * <p> * The sequence of arguments must [consist] of objects corresponding, in order, * to the invokable operation's {@link Op.Invokable#parameters() parameters}. If * the invokable operation {@link Op.Invokable#capturedValues() captures values} * then the sequence of arguments must be appended with objects corresponding, * in order, to the captured values. * * @param l the lookup to use for interpreting reflective operations. * @param op the invokeable operation to interpret. * @param args the invokeable's arguments appended with captured arguments, if any. * @return the interpreter result of invokable operation. * @param <T> the type of Invokable. * @throws InterpreterException if there is a failure to interpret * @throws Throwable if interpretation results in the throwing of an uncaught exception */ public static <T extends Op & Op.Invokable> Object invoke(MethodHandles.Lookup l, T op, Object... args) { // ...
  • 135.
    135/172 Interpreter for CodeModels  Yes, an equivalent of eval()! – JavaScript – Python  In pure Java!
  • 136.
    136/172 Interpreter for CodeModels final Method distanceMethod = Main.class.getDeclaredMethod( "distance", double.class, double.class); final CoreOp.FuncOp distanceFuncOp = Op.ofMethod(distanceMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke( MethodHandles.lookup(), distanceFuncOp, 10, 2); System.out.println(resultsInterpreted1); final CoreOp.FuncOp distanceFuncOpSSA = SSA.transform(distanceFuncOp); final Double resultsInterpreted2 = (Double) Interpreter.invoke( MethodHandles.lookup(), distanceFuncOpSSA, 42, 2); System.out.println(resultsInterpreted2);
  • 137.
    137/172 Interpreter for CodeModels final Method distanceMethod = Main.class.getDeclaredMethod( "distance", double.class, double.class); final CoreOp.FuncOp distanceFuncOp = Op.ofMethod(distanceMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke( MethodHandles.lookup(), distanceFuncOp, 10, 2); System.out.println(resultsInterpreted1); final CoreOp.FuncOp distanceFuncOpSSA = SSA.transform(distanceFuncOp); final Double resultsInterpreted2 = (Double) Interpreter.invoke( MethodHandles.lookup(), distanceFuncOpSSA, 42, 2); System.out.println(resultsInterpreted2); 8 40
  • 138.
    138/172 Interpreter for CodeModels https://www.pinterest.com/pin/697213586035124567/
  • 139.
    139/172 Interpreter for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10); System.out.println(resultsInterpreted1); final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> { final CopyContext cc = builder.context(); if (op instanceof CoreOp.SubOp subOp) { final Op.Result inputResult = subOp.result(); final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast"); final Op.Result rhs = (Op.Result) cc.getProperty("last"); final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs)); cc.mapValue(inputResult, outputResult); } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) { final Op.Result result = builder.op(varLoadOp); cc.putProperty("beforeLast", cc.getProperty("last")); cc.putProperty("last", result); } else { builder.op(op); } return builder; }); final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10); System.out.println(resultsInterpreted2);
  • 140.
    140/172 Interpreter for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10); System.out.println(resultsInterpreted1); final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> { final CopyContext cc = builder.context(); if (op instanceof CoreOp.SubOp subOp) { final Op.Result inputResult = subOp.result(); final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast"); final Op.Result rhs = (Op.Result) cc.getProperty("last"); final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs)); cc.mapValue(inputResult, outputResult); } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) { final Op.Result result = builder.op(varLoadOp); cc.putProperty("beforeLast", cc.getProperty("last")); cc.putProperty("last", result); } else { builder.op(op); } return builder; }); final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10); System.out.println(resultsInterpreted2);
  • 141.
    141/172 Interpreter for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10); System.out.println(resultsInterpreted1); final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> { final CopyContext cc = builder.context(); if (op instanceof CoreOp.SubOp subOp) { final Op.Result inputResult = subOp.result(); final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast"); final Op.Result rhs = (Op.Result) cc.getProperty("last"); final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs)); cc.mapValue(inputResult, outputResult); } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) { final Op.Result result = builder.op(varLoadOp); cc.putProperty("beforeLast", cc.getProperty("last")); cc.putProperty("last", result); } else { builder.op(op); } return builder; }); final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10); System.out.println(resultsInterpreted2); 22
  • 142.
    142/172 Interpreter for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10); System.out.println(resultsInterpreted1); final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> { final CopyContext cc = builder.context(); if (op instanceof CoreOp.SubOp subOp) { final Op.Result inputResult = subOp.result(); final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast"); final Op.Result rhs = (Op.Result) cc.getProperty("last"); final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs)); cc.mapValue(inputResult, outputResult); } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) { final Op.Result result = builder.op(varLoadOp); cc.putProperty("beforeLast", cc.getProperty("last")); cc.putProperty("last", result); } else { builder.op(op); } return builder; }); final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10); System.out.println(resultsInterpreted2); 22
  • 143.
    143/172 Interpreter for CodeModels final Method subMethod = Main.class.getDeclaredMethod("sub", double.class, double.class); final CoreOp.FuncOp funcOp1 = Op.ofMethod(subMethod).get(); final Double resultsInterpreted1 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp1, 32, 10); System.out.println(resultsInterpreted1); final CoreOp.FuncOp funcOp2 = funcOp1.transform((builder, op) -> { final CopyContext cc = builder.context(); if (op instanceof CoreOp.SubOp subOp) { final Op.Result inputResult = subOp.result(); final Op.Result lhs = (Op.Result) cc.getProperty("beforeLast"); final Op.Result rhs = (Op.Result) cc.getProperty("last"); final Op.Result outputResult = builder.op(CoreOp.add(lhs, rhs)); cc.mapValue(inputResult, outputResult); } else if (op instanceof CoreOp.VarAccessOp.VarLoadOp varLoadOp) { final Op.Result result = builder.op(varLoadOp); cc.putProperty("beforeLast", cc.getProperty("last")); cc.putProperty("last", result); } else { builder.op(op); } return builder; }); final Double resultsInterpreted2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp2, 32, 10); System.out.println(resultsInterpreted2); 22 42
  • 144.
    144/172 Example f(x, y) =x × (-sin(x × y) + y) × 4 ∂f(x, y)/∂x = (-sin(x × y) + y - x × cos(x × y) × y) × 4
  • 145.
    145/172 Example  Origin @CodeReflection static doublef(final double x, final double y) { return x * (-Math.sin(x * y) + y) * 4.0d; } static double df_dx(double x, double y) { return (-Math.sin(x * y) + y - x * Math.cos(x * y) * y) * 4.0d; }
  • 146.
    146/172 Example  Transformation final Methodf = Main.class.getDeclaredMethod("f", double.class, double.class); final Double result_f1 = f(2, 3); System.out.println(result_f1); final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get(); final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f); final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3); System.out.println(result_f2); final Double result_df_dx1 = df_dx(2, 3); System.out.println(result_df_dx1); final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0); final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x)); final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3); System.out.println(result_df_dx2);
  • 147.
    147/172 Example  Transformation final Methodf = Main.class.getDeclaredMethod("f", double.class, double.class); final Double result_f1 = f(2, 3); System.out.println(result_f1); final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get(); final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f); final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3); System.out.println(result_f2); final Double result_df_dx1 = df_dx(2, 3); System.out.println(result_df_dx1); final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0); final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x)); final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3); System.out.println(result_df_dx2);
  • 148.
    148/172 Example  Transformation final Methodf = Main.class.getDeclaredMethod("f", double.class, double.class); final Double result_f1 = f(2, 3); System.out.println(result_f1); final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get(); final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f); final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3); System.out.println(result_f2); final Double result_df_dx1 = df_dx(2, 3); System.out.println(result_df_dx1); final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0); final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x)); final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3); System.out.println(result_df_dx2); The differentiation happens here
  • 149.
    149/172 final Method f= Main.class.getDeclaredMethod("f", double.class, double.class); final Double result_f1 = f(2, 3); System.out.println(result_f1); final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get(); final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f); final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3); System.out.println(result_f2); final Double result_df_dx1 = df_dx(2, 3); System.out.println(result_df_dx1); final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0); final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x)); final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3); System.out.println(result_df_dx2); Example  Results – f(2, 3) = 2 × (-sin(2 × 3) + 3) × 4 = 26.235323985591407 – ∂f(2, 3)/∂x = (-sin(2 × 3) + 3 - 2 × cos(2 × 3) × 3) × 4 = -9.92642488681308
  • 150.
    150/172 final Method f= Main.class.getDeclaredMethod("f", double.class, double.class); final Double result_f1 = f(2, 3); System.out.println(result_f1); final CoreOp.FuncOp funcOp_f = Op.ofMethod(f).get(); final CoreOp.FuncOp funcOp_f_SSA = SSA.transform(funcOp_f); final Double result_f2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_f_SSA, 2, 3); System.out.println(result_f2); final Double result_df_dx1 = df_dx(2, 3); System.out.println(result_df_dx1); final Block.Parameter x = funcOp_f_SSA.body().entryBlock().parameters().get(0); final CoreOp.FuncOp funcOp_df_dx = ExpressionElimination.eliminate(ForwardDifferentiation.partialDiff(funcOp_f_SSA, x)); final Double result_df_dx2 = (Double) Interpreter.invoke(MethodHandles.lookup(), funcOp_df_dx, 2, 3); System.out.println(result_df_dx2); Example  Results – f(2, 3) = 2 × (-sin(2 × 3) + 3) × 4 = 26.235323985591407 – ∂f(2, 3)/∂x = (-sin(2 × 3) + 3 - 2 × cos(2 × 3) × 3) × 4 = -9.92642488681308 26.235323985591407 26.235323985591407 -9.92642488681308 -9.92642488681308
  • 151.
    151/172 Other Example  EmulatingC# LINQ in Java – Language INtegrated Query
  • 152.
  • 153.
    153/172 Questions  In Java –How to best open JVM’s closed world? – How to best bridge memory models?
  • 154.
    154/172 Answers  In Java –How to best open JVM’s closed world? • Panama • Babylon – How to best bridge memory models? • Panama • Valhalla
  • 155.
    155/172 The Isthmus inthe JVM 1. Syntax: lambdas vs. function pointers, no C macros, no C++ templates 2. Naming: naming and scoping 3. Data types: Booleans, strings, which always have headers 4. Storage management: many native libraries operate through pointers to memory, garbage collection 5. Exceptions: C++ and Java exceptions behave differently; C APIs sometimes require ad hoc polling for errors 6. Semantics: Java strings are immutable while C “strings” are character arrays, C++ strings are yet different 7. Performance: strings, boxing, copying cause performance “potholes” 8. Safety: the JVM must continue to operate correctly even in the face of errors or abuse of any single API https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 156.
    156/172 The Isthmus inthe JVM 1. Syntax: lambdas vs. function pointers, no C macros, no C++ templates  With project Panama, possible to manipulate C pointers https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 157.
    157/172 The Isthmus inthe JVM 2. Naming: naming and scoping  Nothing much here… https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 158.
    158/172 The Isthmus inthe JVM 3. Data types: Booleans, strings, which always have headers  With Project Valhalla, possible to create value classes/objects https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 159.
    159/172 The Isthmus inthe JVM 4. Storage management: many native libraries operate through pointers to memory, garbage collection  With Project Panama, possible to manipulate memory from Java https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 160.
    160/172 The Isthmus inthe JVM 5. Exceptions: C++ and Java exceptions behave differently; C APIs sometimes require ad hoc polling for errors  With Project Babylon, possible to rewrite code automagically https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 161.
    161/172 The Isthmus inthe JVM 6. Semantics: Java strings are immutable while C “strings” are character arrays, C++ strings are yet different  With Project Babylon, possible to rewrite code automagically https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 162.
    162/172 The Isthmus inthe JVM 7. Performance: strings, boxing, copying cause performance “potholes”  With Project Valhalla, possible to have “primitive” performance https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 163.
    163/172 The Isthmus inthe JVM 8. Safety: the JVM must continue to operate correctly even in the face of errors or abuse of any single API  With Project Panama, more Java code, less C code, less risks https://cr.openjdk.org/~jrose/panama/isthmus-in-the-vm-2014.html
  • 164.
  • 165.
  • 166.
    166/172 With Such AnApproach final OpenAiChatModel model = OpenAiChatModel.builder().apiKey(Main.API_KEY) .modelName(OpenAiChatModelName.GPT_4_O_MINI).build(); final String answer = model.chat("Give me the advantages and disadvantages of Java"); System.out.println(answer);
  • 167.
    167/172 With Such AnApproach final OpenAiChatModel model = OpenAiChatModel.builder().apiKey(Main.API_KEY) .modelName(OpenAiChatModelName.GPT_4_O_MINI).build(); final String answer = model.chat("Give me the advantages and disadvantages of Java"); System.out.println(answer); Java is a widely-used programming language known for its versatility, portability, and robust nature. Here are some advantages and disadvantages of using Java: ### Advantages of Java 1. **Platform Independence**: Java is designed to be platform-independent at both the source and binary levels, thanks to the Java Virtual Machine (JVM). This allows developers to write code once and run it anywhere (Write Once, Run Anywhere - WORA). [...] 8. **Mature Ecosystem**: Java has a mature ecosystem with enterprise-level solutions, making it a preferred choice for large-scale applications, including web and mobile development. ### Disadvantages of Java 1. **Performance**: Java can be slower than some compiled languages (such as C or C++) due to the overhead of the JVM and garbage collection, making it less suitable for performance-critical applications. [...] 8. **Dependence on JVM**: Java applications require the Java Runtime Environment (JRE) to run, which may not be available in all environments. In conclusion, Java is a powerful and versatile language with many advantages, particularly in enterprise and cross- platform applications. However, developers should consider its disadvantages when selecting a programming language for specific projects.
  • 168.
    168/172 With Such AnApproach  Actually… https://github.com/langchain4j/langchain4j/blob/main/langchain4j-open- ai/src/main/java/dev/langchain4j/model/openai/OpenAiChatModel.java this.client = OpenAiClient.builder() .httpClientBuilder(builder.httpClientBuilder) .baseUrl(getOrDefault(builder.baseUrl, DEFAULT_OPENAI_URL)) .apiKey(builder.apiKey) .organizationId(builder.organizationId) .projectId(builder.projectId) .connectTimeout(getOrDefault(builder.timeout, ofSeconds(15))) .readTimeout(getOrDefault(builder.timeout, ofSeconds(60))) .logRequests(getOrDefault(builder.logRequests, false)) .logResponses(getOrDefault(builder.logResponses, false)) .userAgent(DEFAULT_USER_AGENT) .customHeaders(builder.customHeaders) .build();
  • 169.
    169/172 With Such AnApproach  Actually… https://github.com/langchain4j/langchain4j/blob/main/langchain4j-open- ai/src/main/java/dev/langchain4j/model/openai/OpenAiChatModel.java this.client = OpenAiClient.builder() .httpClientBuilder(builder.httpClientBuilder) .baseUrl(getOrDefault(builder.baseUrl, DEFAULT_OPENAI_URL)) .apiKey(builder.apiKey) .organizationId(builder.organizationId) .projectId(builder.projectId) .connectTimeout(getOrDefault(builder.timeout, ofSeconds(15))) .readTimeout(getOrDefault(builder.timeout, ofSeconds(60))) .logRequests(getOrDefault(builder.logRequests, false)) .logResponses(getOrDefault(builder.logResponses, false)) .userAgent(DEFAULT_USER_AGENT) .customHeaders(builder.customHeaders) .build(); It’s a REST call!
  • 170.
    170/172 With Such AnApproach  Three ways for language interoperability – REST APIs and such – Script engines – FFIs  They have different (dis)advantages!
  • 171.
    171/172 With Such AnApproach  REST APIs and such – Simple – Slow, duplications  Script engines – Complex – Fast, some duplications  FFIs – Convoluted – Fast, no duplications
  • 172.
    172/172 With Such AnApproach  REST APIs and such – Simple – Slow, duplications  Script engines – Complex – Fast, some duplications  FFIs – Convoluted – Very fast, no duplications With Projects Panama, Valhalla, and Babylon!