Vortrag-Bad-Honnef/Vortrag/main.tex
2024-07-20 01:06:27 +02:00

455 lines
15 KiB
TeX

\documentclass[aspectratio=43]{beamer}
\usepackage{lmodern} % Add the lmodern package to fix missing font shapes
\usepackage{beamerthemeDHBW} % Include the package
\usepackage[overlay, absolute]{textpos}
\usepackage{bookmark}
\usepackage{pgfplots}
\usepackage[ngerman]{babel}
\usepackage{tikz}
\usepackage{amssymb} % Add the amssymb package to fix missing font shape
\usepackage{listings}
\usepackage{tcolorbox}
\newcommand{\internetadresse}{https://www.dhbw-stuttgart.de}
\pgfplotsset{compat=1.18}
\lstset{
basicstyle=\ttfamily\scriptsize,
keywordstyle=\bfseries,
commentstyle=\color{green!50!black},
escapeinside={(*@}{@*)},
numbers=left,
numberstyle=\tiny\color{gray},
frame=single,
backgroundcolor=\color{lightgray!10},
showspaces=false,
showstringspaces=false,
showtabs=false,
breaklines=true,
tabsize=4
}
%Information to be included in the title page:
\title{Java-TX Compiler in Java-TX}
\subtitle{Bad Honnef 2024}
\author{Julian Schmidt}
\institute{DHBW Stuttgart}
\date{2024}
\usetheme{DHBW}
\begin{document}
\maketitle
\begin{frame}[fragile]
\frametitle{Motivation I}
\begin{itemize}
\item Welche Features fehlen noch in Java-TX?
\item Welche Bugs gibt es?
\item Vorteile/Nachteile zu Java in der Praxis
\item Wie performant ist Java-TX für \glqq{}größere\grqq{} Projekte?
\end{itemize}
\begin{visibleenv}<2>
\begin{table}
\begin{tabular}{ l | c | c }
Language & files & code \\
\hline \hline
Java & 247 & 17958 \\
ANTLR Grammar & 2 & 771 \\
\hline
SUM & 249 & 18729 \\
\end{tabular}
\end{table}
\end{visibleenv}
\end{frame}
\begin{frame}
\frametitle{Motivation II}
\begin{center}
\begin{tikzpicture}[scale=3]
\draw<2> (1,0) -- (0,0) -- (0,1) -- (3,1) -- (3,0) -- (2,0) -- (2, -1.1) -- (1, -1.1) -- cycle;
\node<2> at (0.5, 0.5) {JTX};
\node<2> at (1.5, -0.55) {JTX};
\node<2> at (2.5, 0.5) {BC};
\draw (3.1,-1.1) -- (2.1,-1.1) -- (2.1,-0.1) -- (5.1,-0.1) -- (5.1,-1.1) -- (4.1,-1.1) -- (4.1, -2.2) -- (3.1, -2.2) -- cycle;
\node at (2.6, -0.6) {JTX};
\node at (3.6, -1.6) {JAVA};
\node at (4.6, -0.6) {BC};
\end{tikzpicture}
\end{center}
\end{frame}
\begin{frame}[fragile]
\frametitle{JavaTX}
\begin{itemize}
\item Programmiersprache basierend auf Java 8
\item Globale Typinferenz
\item Lambda-Ausdrücke sind getypt
\item Überladung von Funktionstypen
\item Automatisches Überladen von Funktionen
\item Automatisches generieren von Generics
\item Autoboxing von primitiven Datentypen
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Vergleich Sourcecode Java - Java-TX}
\begin{columns}[T]
\begin{onlyenv}<0->
\begin{column}{0.5\textwidth}
\begin{lstlisting}[language=java]
public class FunNClass extends ClassOrInterface {
private static (*@\alert<2,4>{GenericDeclarationList}@*)
createGenerics(
(*@\alert<2,4>{List<GenericRefType>}@*) funNParams) {
var generics =
new ArrayList<(*@\alert<2>{GenericTypeVar}@*)>();
for ((*@\alert<2>{GenericRefType}@*) param : funNParams) {
generics.add(...);
}
return new GenericDeclarationList(generics, new NullToken());
}
}
\end{lstlisting}
\end{column}
\end{onlyenv}
\begin{column}{0.5\textwidth}
\begin{onlyenv}<-2>
\begin{lstlisting}[language=java, backgroundcolor=\color{red!10}]
public class FunNClass extends ClassOrInterface {
private static
createGenerics(
funNParams) {
var generics =
new ArrayList<>();
for (param : funNParams) {
generics.add(...);
}
return new GenericDeclarationList(generics, new NullToken());
}
}
\end{lstlisting}
\end{onlyenv}
\begin{onlyenv}<3->
\begin{lstlisting}[language=java, backgroundcolor=\color{green!10}]
public class FunNClass extends ClassOrInterface {
private static (*@\alert<4>{GenericDeclarationList}@*)
createGenerics(
(*@\alert<4>{Iterable<? extends GenericRefType>}@*) funNParams) {
ArrayList<GenericTypeVar> generics =
new ArrayList<GenericTypeVar>();
for (GenericRefType param : funNParams) {
generics.add(...);
}
return new GenericDeclarationList(generics, new NullToken());
}
}
\end{lstlisting}
\end{onlyenv}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{Aufbau der Umgebung I}
\begin{enumerate}
\item Compiler soll sukzessive in Java-TX umgeschrieben werden
\item Umgebung mit .java und .jav Dateien
\item Ziel: Auf JVM ausführbare .class Dateien
\end{enumerate}
\end{frame}
\begin{frame}[fragile]
\frametitle{Aufbau der Umgebung II - make}
Erster Ansatz mit make:
\begin{lstlisting}
# Use find to locate all .java and .jav files recursively
JAVASOURCES := $(shell find $(SRCDIR) -name '*.java')
JAVSOURCES := $(shell find $(SRCDIR) -name '*.jav')
# Convert .java/.jav files to .class files with the same directory structure
JAVACLASSES := $(patsubst $(SRCDIR)/%.java,$(DESTDIR)/%.class,$(JAVASOURCES))
JAVCLASSES := $(patsubst $(SRCDIR)/%.jav,$(DESTDIR)/%.class,$(JAVSOURCES))
# Rule for compiling .jav files
$(DESTDIR)/%.class: $(SRCDIR)/%.jav
java -jar $(JTX) -d "$(dir $@)" -cp "$(SRCDIR):$(DESTDIR):target/dependencies/" $<
# Rule for compiling .java files
$(DESTDIR)/%.class: $(SRCDIR)/%.java
$(JC) -nowarn -d $(DESTDIR) -cp "$(SRCDIR):$(DESTDIR):target/dependencies/*" $(JFLAGS) $<
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Aufbau der Umgebung III}
Probleme:
\begin{enumerate}
\item javac compiliert und trackt Änderungen von Abhängigkeiten automatisch
\item javac ist sehr langsam wenn für jede Datei einzeln aufgerufen (mehrfache Compilierungen + JVM overhead)
\end{enumerate}
\begin{columns}[T]
\begin{column}{0.5\textwidth}
\begin{lstlisting}
javac src/main/java/de/dhbwstuttgart/typedeployment/TypeInsert.java
javac src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java
...
javac src/main/java/Main.java
\end{lstlisting}
$\sim{}$5min Compilerzeit
\end{column}
\begin{column}{0.5\textwidth}
\begin{lstlisting}
javac src/main/java/de/dhbwstuttgart/typedeployment/TypeInsert.java src/main/java/de/dhbwstuttgart/typedeployment/TypeInsertPlacer.java ... src/main/java/Main.java
\end{lstlisting}
$\sim{}$2sec Compilerzeit
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{Aufbau der Umgebung IV - compile script}
\begin{enumerate}
\item Lese alle Sourcecode Dateien (*.jav, *.java)
\item Filtere die Dateien, die neu compiliert werden müssen
\item Rufe den Compiler einmal mit allen Sourcefiles als Argumente auf
\lstinline!javac -d "$DESTDIR" -cp "$SRCDIR:$DESTDIR:target/dependencies/*" $JAVAC_FLAGS "${JAVA_CHANGED[@]}"!
\end{enumerate}
% \begin{enumerate}
% \item Suche rekursiv alle .java und .jav Dateien im Quellverzeichnis und speichere sie jeweils in einer Liste
% \item Überprüfe für jede Quelldatei, ob die zugehörige .class Datei im Zielverzeichnis existiert und ob die Zieldatei neuer als die Quelldatei ist
% \begin{itemize}
% \item Wenn ja, gehe weiter zur nächsten Datei
% \item Wenn nein, füge die Quelldatei zur Liste der zu kompilierenden Dateien hinzu
% \end{itemize}
% \vspace*{-\baselineskip}
% \item Rufe den Java-TX Compiler mit allen Dateien in der jav-Liste als Argumente auf
% \lstinline{java -jar $JAVATX_COMPILER_PATH -d $DESTDIR -cp "$SRCDIR:$DESTDIR:target/dependencies/" ${JAV_CHANGED[@]}}
% \item Rufe den javac Compiler mit allen Dateien in der java-Liste als Argumente auf
% \lstinline{javac -d $DESTDIR -cp "$SRCDIR:$DESTDIR:target/dependencies/*" $JAVAC_FLAGS ${JAVA_CHANGED[@]}}
% \end{enumerate}
\end{frame}
% \begin{frame}[fragile]{Bugübersicht}
% \begin{center}
% \begin{tikzpicture} \begin{axis}[ ybar, enlargelimits=0.15, legend style={at={(0.
% 5,-0.3)}, anchor=north,legend columns=-1}, ylabel={amount}, symbolic x
% coords={open,closed}, xtick=data, nodes near coords, nodes near coords
% align={vertical}, width=0.7\textwidth, height=10cm, bar width=2cm]
% \addplot coordinates {(open,1) (closed,25) };
% \addplot coordinates {(open,3) (closed,18) };
% \legend{Bugs,Feature Requests}
% \end{axis}
% \end{tikzpicture}
% \end{center}
% \end{frame}
\begin{frame}[fragile]{Primitive Typen in Java-TX}
\begin{itemize}
\item Java erlaubt neben Referenztypen auch primitive Datentypen (int, boolean, ...)
\item Java-TX erlaubt primitive Datentypen zwar im Quellcode, wandelt diese aber in die korrespondierende Wrapperklasse um (Integer, Boolean, ...)
\end{itemize}
\begin{columns}[T]
\begin{column}{0.5\textwidth}
\begin{lstlisting}[language=java]
int a = 10;
boolean b = true;
float c = 10.0f;
\end{lstlisting}
\end{column}
\begin{column}{0.5\textwidth}
\begin{lstlisting}[language=java]
Integer var1 = null;
var1 = 10;
Boolean var2 = null;
var2 = true;
Float var3 = null;
var3 = 10.0F;
\end{lstlisting}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{Überschreiben von Methoden II}
\begin{itemize}
\item In Java: Methoden nicht anhand von Rückgabewert überschreibbar
\end{itemsize}
\begin{lstlisting}[language=java]
public class Bar {
int foo(Object obj){return 0;}
boolean foo(Object obj){return false;}
}
\end{lstlisting}
\begin{lstlisting}
Bar.java:3: Fehler: Methode foo(Object) ist bereits in Klasse Bar definiert
boolean foo(Object obj){return false;}
^
\end{lstlisting}
\begin{itemize}
\item Aber: Generell auf JVM lauffähig
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Überschreiben von Methoden II}
\begin{itemize}
\item Überschreiben von Java Methoden mit primitiven Datentypen als Parameter funktionierte nicht
\end{itemize}
\vspace*{-\baselineskip}
\begin{lstlisting}[language=java]
public boolean equals(Object obj);
\end{lstlisting}
\begin{lstlisting}[language=java, backgroundcolor=\color{red!10}]
public class Foo {
equals(Object o){
return false;
}
}
\end{lstlisting}
\begin{lstlisting}[language=java]
public class Foo {
public Foo() {}
Boolean equals(Object var1) {
return false;
}
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Überschreiben von Methoden III}
\begin{itemize}
\item Lösung: Wenn Methodensignatur eines Supertyps sich nur in primitiven-/Wrapper-Datentypen unterscheidet, werden Typen vom Supertyp in Subtyp substituiert
\end{itemize}
\begin{lstlisting}[language=java, backgroundcolor=\color{red!10}]
public class Foo {
equals(Object o){
return false;
}
}
\end{lstlisting}
\begin{lstlisting}[language=java]
public class Foo {
public Foo() {}
boolean equals(Object var1) {
return false;
}
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Kompatibilität mit funktionalen Interfaces I}
\begin{itemize}
\item In Java haben Lambda Ausdrücke als Target Type ein funktionales Interface z.B. java.util.function.Function
\begin{lstlisting}[language=java]
Function<Integer, Integer> func = x -> x*2;
\end{lstlisting}
\item Java-TX unterstützt echte Funktionstypen
\begin{lstlisting}[language=java, backgroundcolor=\color{red!10}]
var func = x -> x*2;
func: Fun1$$<Integer, Integer>
\end{lstlisting}
\end{itemize}
\end{frame}
\begin{frame}[fragile]{Kompatibilität mit funktionalen Interfaces II}
\begin{itemize}
\item Java ist nominal typisierte Sprache
\item Problem: Lambda Ausdrücke haben in Java-TX einen FunN\$\$ Typ (für N = \#Parameter)
\item Aber: Java Bibliotheken wie Stream erwarten verschiedene funktionale Interfaces
\item Daher: Lambda Ausdrücke müssen je nach Kontext erwartetes funktionales Interface als Target Typ haben
\end{itemize}
\begin{lstlisting}[language=java]
public class Main {
main() {
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5));
return list.stream().map(x -> x*2).toList();
}
}
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Kompatibilität mit funktionalen Interfaces III}
\begin{lstlisting}[language=java]
<R> Stream<R> map(Function<? super T, ? extends R> var1);
\end{lstlisting}
\begin{lstlisting}[language=java]
public interface Function<T, R> {
R apply(T var1);
}
\end{lstlisting}
\vspace*{\baselineskip}
\begin{itemize}
\item Eigentlich würde Java-TX \lstinline[basicstyle=\normalsize]|Fun1$$<Integer, Integer>| inferieren
\item Aber: Stream.map erwartet \lstinline[basicstyle=\normalsize]|Function<? super T, ? extends R>|
\end{itemize}
\begin{lstlisting}[language=java]
...
3: invokedynamic #41, 0 // InvokeDynamic #0:apply:(LFoo;)LFun1$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$;
//Invalid Bytecode
5: invokeinterface #45, 2 // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
...
\end{lstlisting}
\end{frame}
\begin{frame}[fragile]{Kompatibilität mit funktionalen Interfaces IV}
\begin{lstlisting}[language=java]
...
50: invokedynamic #60, 0 // InvokeDynamic #0:apply:(LFoo;)Ljava/util/function/Function;
55: invokeinterface #66, 2 // InterfaceMethod java/util/stream/Stream.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream;
...
\end{lstlisting}
\end{frame}
\begin{frame}{Fazit}
Vorteile:
\begin{itemize}
\item Programmierer muss weniger Typen explizit angeben
\item Funktionstypen erlauben übersichtlichere Subtypisierung von anonymen Funktionen als Java
\end{itemize}
Nachteile:
\begin{itemize}
\item (Alle verwendeten/berückstichtigten Typen müssen manuell importiert werden) \\
\(\rightarrow\) Der Programmierer muss schon wissen, welche Typen in Frage kommen
\item Es ist möglich, dass ein ungewünschter Typ inferiert wird
\item Aktuell begrenzte Sprachfeatures \& vermutlich einige Bugs
\end{itemize}
\end{frame}
\begin{frame}{Fazit}
Weg ist noch weit ... \\
Aktuell $\sim{}3\%$ der Java Dateien in Java-TX übersetzt
\begin{center}
\begin{tikzpicture} \begin{axis}[ ybar, enlargelimits=0.15, legend style={at={(0.
5,-0.1)}, anchor=north,legend columns=-1}, ylabel={amount}, symbolic x
coords={open,closed}, xtick=data, nodes near coords, nodes near coords
align={vertical}, width=0.7\textwidth, height=10cm, bar width=2cm]
\addplot coordinates {(open,1) (closed,25) };
\addplot coordinates {(open,3) (closed,18) };
\legend{Bugs,Feature Requests}
\end{axis}
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}