• No results found

The Usefulness of Programming Languages Beyond Java

N/A
N/A
Protected

Academic year: 2021

Share "The Usefulness of Programming Languages Beyond Java"

Copied!
18
0
0

Loading.... (view fulltext now)

Full text

(1)

Linköping university | Department of Computer and Information Science Bachelor’s Thesis, 16 hp | Bachelor’s Programme in Programming Spring term 2019 | LIU-IDA/LITH-EX-G--19/032--SE

The Usefulness of Programming

Languages Beyond Java

Alexander Jonsson

Supervisor: Jalal Maleki Examiner: Rita Kovordanyi

Linköping universitet SE-581 83 Linköping 013-28 10 00, www.liu.se

(2)

1

The Usefulness of Programming Languages Beyond Java

Alexander Jonsson

Linköping, Sweden

alejo720@student.liu.se

1 ABSTRACT

Beyond Java, new programming languages running on the Java virtual machine (JVM) have been developed, such as Kotlin, Scala, JRuby and Clojure amongst others. Since all these languages compile to Java, it is theoretically possible to use them together in the same project. This paper investigates if this is possible and what benefits it gives using those programming languages together in a project. The languages chosen to be used together were Jython, Scala and Kotlin.

An experiment was conducted where in a single project, each programming language was assigned a problem to be solved. The experiment was then conducted in two iterations where in each iteration, the problems to be solved was assigned to a different programming language.

Our experiment show that using these languages together in a project was possible but resulted in some complications that need to be addressed. It was also shown that the following division amongst the languages worked best in the present use case: Jython for graphical handling, Scala for calculating and computing and Kotlin for data-handling.

2 INTRODUCTION

Java is one of the most popular programming languages today. According to Oracle, several billion devices were running Java in 2010 [1]. Also, Java had the most job demand in 2017 [2]. Java was created with the purpose of eliminating the recurring hardware incompatibility problems for software developers. The problems are caused by the fact that different hardware requires different instructions for doing the same work. This issue was solved by implementing Java on a Java Virtual Machine (JVM). A JVM is basically a virtual computer, giving the CPU instructions according to the given Java-formatted bytecode [3]

.

Therefore, Java code can be run on any device having the JVM installed, making Java code platform independent.

Given its popularity and platform independency, it is not surprising that programming languages other than Java have been created to run on the JVM. Examples of such programming languages are Kotlin, Scala, JRuby, Jython, Clojure and many others. Since all those programming languages are compiled to JVM code in the end, it should be possible to combine multiple languages together in a project regardless of the languages’ properties. For example, if the language is interpreted, compiled, dynamically typed or static typed. All these types of programming languages have

their pros and cons. For example, the JVM is designed for Java which is a statically typed programming language, meaning it is not optimized for dynamically typed programming languages running on the JVM [4, 5], such as JRuby and Jython. Though, dynamic typing can be beneficial in some cases, for example when creating a short program [6]. In the end, the desired properties of a programming language are partly dependent on what problem is going to be solved [7].

The purpose of this work is to decide if it is possible to use multiple programming languages running on the JVM together in a single project. Also, we try to decide if this is relevant by looking at the benefits this gives. To answer this, the following research questions are formulated:

• RQ1: Is it possible to use Jython, Scala and Kotlin in a single project? If that is the case, what problems arise? • RQ2: To what type of programming problems is Jython, Scala or Kotlin the preferred choice when used together in a single project?

2.1 The Scope of This Work

RQ2 will not be answered regarding all types of problems.

The answer is limited based on the problems solved in the experiment. Also, due to insufficient time, not all combinations of programming languages for all problems will be tested. Though, problems out of scope from the experiments will theoretically be discussed.

The following three programming languages running on the JVM is chosen to be investigated:

Jython, a scripting (interpreted) and dynamically typed

programming language.

Scala, compiled and statically typed with support for

functional programming.

Kotlin, compiled and statically typed, commonly used

for Android development.

3 THEORY

Because Jython, Scala and Kotlin all run on the JVM, the JVM is first introduced in the theory section. Next, a short overview of Jython, Scala and Kotlin is given. Then, the different properties of these programming languages, as well as how these properties affect implementation of the JVM are investigated. In the last section, the different programming paradigms used by Jython, Scala and Kotlin are investigated. However, some programming language

(3)

2 concepts that will be used throughout this paper are first described.

3.1 Programming Language Concepts

Typing of a programming language can either be static or

dynamic. Dynamic typing means that a variable’s type is not decided until runtime of a program, whereas static typing means that the type must be declared before running the program.

Purely object-oriented means that all variables are objects

and all operations are method calls, i.e. there are no primitive datatypes [8].

Nullable means that a variable can both have and be assigned

the null value. The null value is used in programming to represent an object with no set value, which can be problematic if not expected. For example, a program will crash if you are trying to access a function on a null value when you were expecting an actual object value.

Programming paradigm is basically a pattern or model in

how to write code. It defines how a programming language is constructed which gives rise to different ways to program.

3.2 Java Virtual Machine

Java was first created with the purpose of being able to run compiled code transferred between networks. The rise of the World Wide Web allowed multiple users with different hardware and network connections access websites. Though, these websites were using HTML which had limited functionality. Therefore, the HotJava browser was created which allowed websites to download compiled Java bytecode that could be run on the website. This was done using the JVM which is basically a virtual computer giving instructions to the CPU from a set of possible instructions specified by the JVM. What instructions to use depends on the implementation of the programming language running on the JVM [3], meaning the implementation affects the performance [9, p. 13]. Though, before going into detail about the programming language’s different properties and how it affects their implementation on the JVM, we will give a brief overview of Jython, Scala and Kotlin.

3.3 Jython

Jython is basically Python that works together with Java. Python is a dynamically typed and interpreted scripting language with high-level functionality and Jython is basically the Python programming language implemented in Java. This means Jython can be run on the JVM, making Jython compatible with Java and other programming languages also running on the JVM [9].

3.4 Scala

Scala is a statically typed and compiled programming language implemented on the JVM. It is both an object-oriented and a functional programming language aimed to be used for creating component-based systems [8].

3.5 Kotlin

Kotlin is just like Scala a statically typed and compiled programming language implemented on the JVM, with support of object-oriented programming. It is mostly used for Android development as a replacement for Java for various reasons including the shorter and cleaner code. Also, Kotlin is not nullable per default, making it safer than Java [10].

3.6 Properties of Jython, Scala and Kotlin

In Appendix 1 some of the most important properties of Jython, Scala and Kotlin can be seen. The different properties of these programming languages can be a potential source of problems when trying to use them in a single project. For example, the data structures are defined for a specific programming language, meaning the data structures are very confined inside its own space [7]. Though, with their own implementation of the JVM for Jython, Scala and Kotlin makes it possible, since the data structures inside the JVM will be the same in the end.

As seen in in Appendix 1 Scala is purely object-oriented while Jython and Kotlin are not. Since there are only primitive and reference types in the JVM [3], all datatypes when compiling Scala code to Java bytecode should technically be references. However, the JVM for Scala is implemented so that all objects representing the typical primitive datatypes (such as int, float and char) are actually converted to a primitive representation inside the JVM [8]. Therefore, the fact that Scala is purely object-oriented should be able to be ignored in regard to RQ1.

Since Scala and Kotlin are both compiled to Java bytecode it would be favorable if Jython also could compile to Java bytecode. Though, since Jython is based on Python, it is an interpreted programming language and cannot be compiled as seen in Appendix 1. However, this is only true per default since it is possible to compile Jython code to JVM class-files packaged to classic “.jar”-files using the “jythonc”-compiler [9, p. 16]. Unfortunately, this is no longer possible in the newer versions of Jython. Instead we must use a work-around. The work-around basically works by importing a Java-interface in Jython, that the Jython-class needs to extend. Then, inside Java the Jython-module is imported and converts the class inside the module to same type as the Java-interface, using an interpreter-object provided by the Jython-package. Note that the Jython types corresponds to a similar Java type and is converted using type coercion [11]. As one could argue, using the work-around results in extra work and could result in overhead regarding the performance. Though, using Jython together with Scala and Kotlin together in a project will most likely require using the work-around. On the contrary, for Jython to be able to import a Java-package (outside of the Java standard library), its JAR-file needs to be added to the CLASSPATH [11]. This should also apply if you are going to import a Scala or Kotlin-package, since the class-files are just like Java, also packaged to a JAR-file.

(4)

3 The default value of a reference is null in the JVM [3] and as seen in Appendix 1, Kotlin is not nullable. Though, it is possible to add a question mark after the datatype to allow variables having the null value [12, p. 202]. Additionally, Kotlin maps imported Java types to nullable Kotlin representation called platform types [13]. Though, when assigning a null value to a Kotlin-variable it will only work when no type is specified, or the type specified includes a question mark. If the type is specified without a question mark it will compile but fail during runtime because the returned type can’t be null. Listing 1 shows an example of how this works. All these ways to allow nullable variables inside Kotlin makes it easier to use Kotlin together with Scala and Jython that both are nullable.

The different properties of Jython, Scala and Kotlin also means they each need their own JVM implementation. The implementation could affect performance in some cases, thus making that language less relevant for solving a specific problem.

As seen in Appendix 1, all programming languages can import Java-packages. Since all of Jython, Scala and Kotlin in the end is Java bytecode, this means they should theoretically be able to be imported just like a Java package as well. Though, the different properties can affect the performance of these imports. For example, Scala supports multi-inheritance while the JVM does not. Therefore, it is required to copy the code from one of the inherited classes into the base class. Also, Scala has no support for static class members. Therefore, Scala must divide the Java classes into a singleton class and a regular class, containing static members and dynamic members respectively [8].

Since JVM was designed for Java, which is a statically typed programming language, the JVM contain instructions for specific datatypes [3] and is not optimized for dynamically typed languages. Up until recently in 2011, there were no support for implementation of dynamic types inside the JVM [14] (more specifically the bytecode instruction invokedynamic was introduced [3]). Therefore, there is still ongoing progress and research regarding optimization and performance of dynamic JVM-languages [4, 5]. As seen in Appendix 1, Jython uses dynamic typing compared to Scala and Kotlin meaning the performance of Jython should be theoretically lower. A practical example of how Jython’s dynamic typing affects the performance is that to speed up the compilation of Jython-code, Java bytecode is generated

1

https://www.scala-lang.org/api/2.12.3/scala/reflect/index.html

during the interpretation of the Jython-code. This bytecode mostly consists of code needed for Python-code in order to run with an implementation of Java, for example Python’s exec function [9, p. 218].

Type erasure means that you force the JVM to decide the type during compilation. This means that for example the declarations List<String> and List<Int> will be seen as List<Any> in the compilation step [12, p. 223]. Therefore, functions with same name but different generic types in the parameter list will not be possible, see example in Listing 2. Though, this can be solved in Kotlin by adding the @JvmName-annotation above the function name [12, p. 224], see example in Listing 3.

Type erasure is also a problem in Scala but can be solved using modules such as ClassTag, TypeTags or Manifest found in Scala’s scala.reflect1 library. The fact that Jython is

dynamically typed prevents code like in Listing 2 in the first place.

Deciding which of Jython, Scala and Kotlin is the best choice for a specific problem is not only affected by its JVM implementation. It is also affected by its properties in general. For example, Jython is said to reduce the amount of code by half compared to Java. Since shorter code is said in many empirical studies to reduce number of bugs [9, p. 9], Jython should in general be a good choice for most programming problem.

XML is commonly used to store configuration or data and Scala makes the handling of XML easy. Furthermore, Scala is also being planned to be extended with support for database query languages [8]. Therefore, Scala could be more relevant when dealing with problems regarding data handling.

Static typing makes type errors be detected during compilation and makes the code stricter in general [15]. This means static typing is often more relevant in a larger project that needs to be maintainable. On the other hand, if one would want to write a smaller program it is often quicker and easier using a programming language with dynamic typing [6].

// Will compile but fail during runtime

val testNull: String = <Java-function returning null>

// Will compile and work during runtime val testNull = <Java-function returning null>

val testNull: String? = <Java-function returning null>

Listing 1. Example of Kotlin platform types and its behavior

fun sort(list: List<String>): Unit = {…} fun sort(list: List<Int>): Unit = {…}

Listing 2. Example of non-compiling code

@JvmName("sortString")

fun sort(list: List<String>): Unit = {…}

@JvmName("sortInt")

fun sort(list: List<Int>): Unit = {…}

(5)

4

3.7 Programming Paradigms

When choosing what programming language to use for a specific problem, it is also relevant to look at the paradigms of that language. The solution to a problem will be different based on the paradigm used. A guideline to decide which paradigm is the best to use is simply to use the paradigm that solves the problem with the least effort. In addition, by having multiple programming paradigms, it naturally requires the programmer to see the world in different views [16].

There are essentially two categories of programming paradigms; stateful and stateless. In both categories data can be created, but stateful paradigms consists of data that can change over time, which is more closely related to our own world. Though, stateless programming typically feels more logical and is easier to make sense about. Examples of stateful programming paradigms are imperative and object-oriented programming, and examples of stateless programming paradigms are functional and logic programming [7].

Jython, Scala and Kotlin all support both the imperative and object-oriented paradigm. Though, Scala also supports the functional programming paradigm [8]. Since the definition of a multiparadigm programming language is that the language must support multiple paradigms [16], all of Jython, Scala and Kotlin are multiparadigm programming languages. Therefore, it is important to note which programming paradigm is used when answering RQ2. The basic and simple definition of an imperative programming language is that it uses statements that changes the state of a program [17]. The typical way of changing the state of a program is to reassign variables.

What defines an object-oriented programming language is the support of creating objects consisting of data and/or operations [18], created from a blueprint called a class. Since these objects are instantiated from a class typically with different values, thus changing the state of the program, it could be said that object-oriented programming languages naturally also becomes imperative.

The main idea behind a functional language is that functions are regarded as values [16]. Also, the functional paradigm is defined as being stateless, meaning the values of variables are never modified. Therefore, data is typically evaluated on the go. Appendix 2 shows an example of using the functional paradigm in Scala. Note that no data is being changed and everything is evaluated on the go. Also, the division expression is a function call, showing another example that Scala is purely object-oriented.

2 https://www.jetbrains.com/idea/. 3https://gradle.org/

4 METHOD

To answer the research questions, an experiment was conducted in where modules were created, each with a different role or problem to solve. The modules were also dependent on one another with each module assigned to either Jython, Scala or Kotlin. Then, the modules were tried to be used together in a project, thus answering RQ1. To also answer RQ2, another iteration of the same experiment was conducted but with reassigned roles between the programming languages. By doing that, the solutions of Jython, Scala and Kotlin could be compared to analyze which of the programming language or programming paradigm was the best choice for the module’s particular problem to be solved. In addition, the performance in time for the different solutions and amount of code was also compared.

In each iteration of the experiment a project was created using JetBrains’s IntelliJ IDEA2 which is an integrated development environment (IDE) designed specifically for Java. In this project three modules were created, one for each programming language. To create the dependency between the modules Gradle3 was used, which is a tool that helps during development of applications, for example with the building of a project.

4.1 The Experiment

The goal of the experiment was to create a program that calculates the average score of movies with a specific genre. This required three fundamental problems to be solved; handling the data of movies, calculating the average score for the specified genre and handling user interaction by allowing the user to specify a genre and graphically display the result. In other words, there was a need for a data-layer, logic-layer and a graphical user interface (GUI). These layers could then in iteration 1 and 2 of the experiment, each be assigned a different programming language. By using this multi-tier architecture, it naturally created dependencies between the modules and each layer gets its own problem to solve. In the next sections it is briefly explained how the modules in the project works.

4.1.1 Data-Layer

The data-layer module works by loading a local CSV-file created from TMDB4, filtering the search based on the specified genre. Without doing any logic it only returns a list with the filtered movies’ average score (it could also return the movies’ title and other interesting information to make the solution more general).

Since the GUI-layer needed all the unique genres for the user to choose from, a function returning a list of strings containing the unique genres was created. This list is

(6)

5 generated simply by searching through each movie’s genres, filtering the unique genres.

4.1.2 Logic-Layer

The logic-layer module works by fetching data about movies obtained from the data-layer, inputting the specified genre received from the GUI-layer. The logic-layer could then calculate the average score by dividing the sum of all movies’ score by the number of movies.

To get all unique genres for the GUI-layer to use, the logic-layer simply calls the function from the data-logic-layer and returns the result.

4.1.3 GUI-Layer

The GUI-layer module is built using the Swing library5. The Swing library is a Java library and is used to build GUI for simple desktop applications. The GUI allows the user to specify a genre from a list of possible genres that is obtained from the logic-layer. Then, when a button is pressed the average score calculated and obtained from the logic-layer is displayed. To make it as simple and quick as possible while programming, the graphical components were only stacked into a grid layout:

• JComboBox: filled with all the possible genres the user can choose from, received from the logic-layer. • JButton: tells the logic-layer to calculate the average

score and graphically updates the result.

• JLabel: used to show the result of the average score and is updated when user presses the button.

4.2 The Experiment – Iteration 1

In the first iteration of the experiment the different roles were randomly assigned as following: Jython for the data-layer, Scala for the logic-layer and Kotlin for the GUI-layer. Note that these assignments of roles require Scala to import a Jython-module allowing the testing of different typing. Also, since Jython is created to import Java-code [9] and not vice versa, it means the work-around explained in section 3.6 is required. Furthermore, these assignments allow the investigation of the fact that Scala is purely object-oriented and nullable while Kotlin is not. Though, there was no case in this experiment where it was desired for Scala to return null to Kotlin. Therefore, a simple function that only returns null was created inside the logic-layer.

4.3 The Experiment – Iteration 2

In the second iteration of the experiment the different roles were assigned as following: Scala for the data-layer, Kotlin for the logic-layer and Jython for the GUI-layer. This

5https://docs.oracle.com/javase/7/docs/api/javax/swing/pack

age-summary.html

assignment allowed all the programming languages to have a new role in the project compared to iteration 1, and therefore a new problem to solve.

Note that these assignments of roles require Jython to import a Kotlin-module. As explained in section 3.6 this means you must build the Kotlin-module and its dependencies to a JAR-file. This JAR-file then needed to be added to the CLASSPATH before running Jython. In addition, these assignments could try out the fact that Jython is dynamically typed while Kotlin is statically typed. Also, by assigning Scala to the data-layer it could practically be tried what is mentioned in section 3.6, that Scala could be a good choice for data-handling.

4.4 The Experiment - Comparison of Iteration 1 and 2

To compare the solutions between the programming languages both iterations were programmed as identical as possible. Though, this was sometimes not desired since the different properties of the languages affects the decision of what language is the preferred choice. For example, Scala supports the functional paradigm which could not be tested if it were to be coded identical as the corresponding module that does not support the functional paradigm.

As explained in the section 3.6, there are factors that should theoretically affect the performance of the different programming languages, such as the work-around needed to import the Jython-module. Before measuring the performance in time, the solutions had to be adjusted to make sure both iterations were as identical as possible. Measuring the time between the solutions of iteration 1 and 2 was simply done by comparing the time before and after running the code, using the Java-library java.time6. Also, lines of code of

the solutions were counted for an additional comparison measurement.

5 RESULT

Using Jython, Scala and Kotlin could be used together in the project in both iterations. Though, during the process of the implementation there were some complications that will be explained in the following sections. The following sections will also show and explain parts of the resulted code that is relevant for the discussion. If you want to have a more detailed look at the complete code, you can download the source code from GitHub7. The graphical result of the program which is identical to both parts is shown in Appendix 3.

5.1 The Experiment – Iteration 1

In Listing 4 we see the Kotlin code executed when the user presses the “calculate”-button. The code gets the user’s

6https://docs.oracle.com/javase/8/docs/api/java/time/packag

e-summary.html

(7)

6 specified genre, tells the logic-layer to calculate the average score based on that genre and updates the JLabel to display the result.

For the logic-layer to work it needs to import the data-layer using the work-around. Listing 5-7 shows the implementation of the work-around in Scala. In Listing 5 we see the creation of a factory class and a call to the create function expecting to return an object with data type DataLayerType. In Listing 6, we can see how this type is defined as a Scala-trait (trait works basically like an interface in other languages) and then implemented by the Jython-module. Then, the Jython-module can be imported, initialized and converted to the data type DataLayerType with the code shown in Listing 7.

When the data-layer has been imported the logic-layer can get the data it needs. In Listing 8 we see how the logic-layer calculates the average score for a specific genre. It divides the sum of the scores obtained from a high-ordered function with the total number of scores.

8https://docs.oracle.com/javase/7/docs/api/java/lang/IllegalS

tateException.html

Listing 9 shows how Jython filters all movies with the specified genre that are used by the logic-layer. High-ordered functions included in Python’s standard library are used to first filter movies with the specified genre and then mapping the score of the movie to a new list. Note that the returned list of Floats will be converted to an Array of Floats with Jython’s type coercion [11], which can be seen in Listing 8 (observe that Array class derives from the Iterable-class).

In Listing 10 we see a simple function in Scala returning null and what happens in Kotlin. The first assignment compiled but threw the exception java.lang.IllegalStateException8

with a message saying that the return value of the function can’t be null. Though, the rest of the assignment worked.

The shown code is the result after some complications were solved. The first complication comes with the work-around. With this work-around there were some problems with the path. To be able to import the required Scala-interface as shown in Listing 6 it was required to be inside the project environment since the package was created as a dependency using Gradle. At the same time, to import the Jython-module from Scala (using the python-interpreter function exec as shown in Listing 7) the path to the Jython-module either had to be hardcoded or added to Jython’s system path. If the path was hardcoded, there were problems with different formatting between Scala and Jython (the python interpreter-object parsed the string as it was, meaning the escaped backslashes needed by Scala were ignored). If instead the Jython-module was added to Jython’s system path the

Scala-val genre: String = genresComboBox.selectedItem.toString()

val score: Float = logicLayer.calculateAverageScore(genre)

val scoreStr = "%.2f".format(score)

avgScoreLabel.text = "Average score of genre " + genre + ": "

+ scoreStr

Listing 4. Kotlin code executed when the button is pressed

val datalayer: DataLayerType = new DataLayerFactory().create()

Listing 5. Creating the data-layer using a factory class

// Scala code

from <package of project> import DataLayerType

trait DataLayerType {

def getMovieScores(genre: String): Array[Float] def getGenres(): Array[String]

}

// Jython code

class DataLayer(DataLayerType): def getMovieScores(self, genre): ...

def getGenres(self): ...

Listing 6. Data-layer implementing the Scala-interface // Importing the Jython-module and getting a reference to the DataLayer-class

var interpreter: PythonInterpreter = new PythonInterpreter()

interpreter.exec("from datalayer import DataLayer")

var buildingClass = interpreter.get("DataLayer")

// create-function returning an initialized and converted objects of DataLayerType-class

def create(): DataLayerType = {

val datalayerObject = buildingClass.__call__() datalayerObject.__tojava__(classOf[DataLayerType]).asInstanceO f[DataLayerType]

}

Listing 7. Importing, initializing and converting the data-layer

def average(list: Iterable[Float]): Float = { list.sum./(list.size)

}

def calculateAverageScore(genre: String): Float = { val movieScores: Array[Float] =

datalayer.getMovieScores(genre) average(movieScores) }

Listing 8. Calculating the average score of a specific genre

def getMovieScores(self, genre):

return map(lambda m: m.score, list(filter(lambda

m: genre in m.genres, self.movies)))

Listing 9. Code filtering all movies by a specific genre

// Scala code

def testNullable(): Movie ={ null

}

// Kotlin code

// Will compile but fail during runtime val testNull: Movie = logicLayer.testNullable()

// Will compile and work during runtime val testNull = logicLayer.testNullable()

val testNull: Movie? = logicLayer.testNullable()

(8)

7 interface could not be imported as it was internally and temporarily added to the CLASSPATH when running inside IntelliJ IDEA. The final fix was to create a symbolic link inside Jython’s system path pointing to the Jython-file inside the project. This allowed the Jython-file to be run as if it would have been inside the project, allowing the import of the Scala-interface. At the same time, Scala could import the Jython-module since it was in Jython’s system path. The second complication arises from the fact that to make the solution more general it was desired to return a dictionary type from Jython containing additional data beyond the movie’s score. Though, there is no type coercion from Jython’s dictionary to Scala [11]. To solve this, a movie-class could be created and included in the work-around, but it was initially decided to use a less verbose solution, returning a string that could be formatted by Scala. The data was split using the vertical bar sign (‘|’), making it possible to split the string into a list, extracting the wanted data. Finally, since in this case there was only a need to get the average scores, a list of floats could simply be returned, which is a possible type coercion [11].

5.2 The Experiment – Iteration 2

In Listing 11 we see what happens when the user presses the “calculate”-button. Just like in iteration 1, the code works by getting the user’s specified genre, telling the logic-layer to calculate the average score based on that genre and displays the result by updating the JLabel.

Calculating the average score in Kotlin was done basically in the same way as we see in Listing 8 from iteration 1. Though, as we can see in Listing 12, we don’t use a high-ordered function to get the sum.

The code in Listing 13 is used to filter the movies by a specified genre which is fundamentally done in the same way as in Listing 9 from iteration 1. Though, note that this time a list of objects of the class Movie is returned instead of a list of Floats.

For the Jython-module to be able to import the Kotlin-package, a packaged JAR-file of Kotlin had to be added to the CLASSPATH. This was solved by first compiling both the Kotlin logic-layer and the Scala data-layer, including their dependencies to a JAR-file. Then, IntelliJ IDEA is configured, as we can see in Figure 1, to add the absolute path of the JAR-files to the CLASSPATH, before running the program.

To make the code as identical as possible when calculating the average score in Kotlin, it was desired to use higher-ordered functions in the same way as in Listing 8 from iteration 1. More specifically, it was desired to use the function map to select all average scores and then use functions such as reduce or sum to calculate the score. The datatype of the returned object from Scala was as seen in Listing 12 from Scala’s standard library. This caused problems when calling high-ordered functions on the object due to syntactic differences (for example, the syntax of lambda expression is different between Scala and Kotlin). In the end, it was decided to simply iterate the movies, adding average score to a sum variable, as shown in Listing 12.

5.3 The Experiment – Comparison of Iteration 1 and 2

Observe that differences between the iterations that are not objective will be discussed in section 6.

Appendix 4 shows how the time in Kotlin was measured using the Java library java.time. Though, it works the same in Jython and Scala.

Appendix 5 roughly shows the difference of the performance in time between iteration 1 and 2. The first column shows the total time it took for the program to initialize and start, and rest of the columns roughly shows how many percent of this total time the different parts took to execute. Though, before conducting these tests the function calculating the average scores shown in Listing 8 had to be temporarily changed to be more identical to the function shown in Listing 12 from iteration 2.

Appendix 6 shows the number of lines of code used for the different modules. Note that this does not include the imports and the code used for the work-around.

6 DISCUSSION

In the following sections, the result will first be discussed with the aim to answer the research questions. Then, the method’s validity will be criticized.

def calculate_score(self):

genre = self.genresComboBox.getSelectedItem()

avgScore = self.logicLayer.calculateAverageScore(genre) scoreStr = "{0:.2f}".format(avgScore)

self.avgScoreLabel.setText("Average score of genre " + genre + ": " + scoreStr)

Listing 11. Jython code executed when button is pressed

fun calculateAverageScore(genre: String): Float { val movies: scala.collection.immutable.List<Movie> = datalayer.getMoviesByGenre(genre)

var sum = 0.0f for (movie in movies) { sum+=movie.avgScore() }

return sum / movies.size() }

Listing 12. Kotlin code calculating the average score for a specified genre

def getMoviesByGenre(genre: String): List[Movie] = { movies.filter(_.genres.contains(genre)).toList }

Listing 13. Scala code filtering movies by the specified genre

(9)

8

6.1 Result – RQ1

As we could see from the experiment it is possible to use Jython, Scala and Kotlin together in a project. Note that used Java libraries such as Swing was easily imported in all programming languages as expected from Appendix 1. Though using the languages in the same project did not come without any problems. These problems will be discussed in the following sections.

6.1.1 The Experiment – Iteration 1

When using and importing Scala code from Kotlin there were no difficulties. Even though Scala is purely object-oriented while Kotlin is not, the datatype Float are in both languages compiled to primitive datatypes inside the JVM, avoiding any problems. Also, as shown in Listing 12, returning null from Scala to Kotlin works as theoretically expected.

When using and importing Jython code from Scala a work-around was required. The work-work-around was theoretically expected to require extra work and overhead in performance. This was proven to be true since as we can see from Listing 5-8, majority of code written for the logic-layer was code used for the work-around. Also, as we can see from Appendix 5, 80% of the time to initializing and starting the program comes from importing the data-layer using the work-around. However, the work-around required Jython to import a Scala-interface where the data types were already defined, meaning that the fact that Scala is statically typed and Jython is dynamically typed did not result in any problems. Though, as explained in section 5.1, it was not optimal if a class representing a movie were to be returned from Jython to Scala.

6.1.2 The Experiment – Iteration 2

Again, there were no problems caused by the fact that Scala is purely object-oriented while Kotlin is not for the same reason as explained in section 6.1.1. Also, Scala did not have to return null to Kotlin, avoiding any problems. Even though there would have been a need to return null it was proven to have worked as shown in Listing 10.

Importing to Jython by adding JAR-files to the CLASSPATH worked as theoretically expected. Also, this time there were no problems returning a class representing a movie from the data-layer to the logic-layer. The Movie-class defined in Scala could be imported and used by Kotlin as shown in Listing 11. Though, as explained from section 5.2, the datatype returned to Kotlin caused some problems. Jython is dynamically typed while Kotlin is statically typed. Though, this didn’t result in any problems because Jython is the Python programming language implemented in 100% Java. Additionally, the JVM has support for dynamic typing, avoiding any problems in this case.

6.2 Result – RQ2

In the following sections, RQ2 is first discussed based on the result of the conducted experiment. Then, RQ2 will be discussed based on general theoretical reasons found outside of the result.

6.2.1 The Experiment – Comparison of Iteration 1 and 2 As we can see from Appendix 5 using the work-around increases the time to initialize and start the program by roughly 6 times. This means that when using Jython in a project together with another programming language running on the JVM, Jython should be avoided to be a dependency to another language. By using Appendix 5 it can also be calculated that using Jython for the data-layer or GUI-layer resulted in 35% or 66% increase in time respectively. This is not surprising since the fact that Jython is dynamically typed was in section 3.6 expected to decrease the performance. This means that in general, one would want to avoid using Jython for the heaviest computations.

As mentioned in section 3.6, Jython reduces amount of code by half compared to Java. From earlier experience, code used for the GUI is usually the part in a program using the most amount of code. This could be caused by the fact that there are many properties and event handling for the many components needed. This also applies to this project where as seen in Appendix 6, the GUI-layer uses at least 50% more lines of code than the logic-layer and data-layer. Since shorter programs are often proven to have less bugs, using Jython for a verbose GUI is concluded to be a relevant choice. Furthermore, using Jython for the GUI-layer avoids Jython being a dependency to another module, which was in this section and section 6.1.1 proven to be costly.

It is also mentioned in section 3.6 that stateful programming paradigms is more connected to the real world and object-oriented paradigm is stateful. In this case, a movie is something connected to our real world, meaning creating a movie-class feels natural while programming. Since all of Jython, Scala and Kotlin support object-oriented programming they are all a relevant choice for this particular problem. Though, importing a class from Jython was not optimal because of the work-around, as explained in section 5.1.

6.2.2 General Discussion – RQ2

The functional paradigm is stateless, meaning it cannot modify data. This means that when facing a problem that only needs to handle given data, one would consider using the functional paradigm. In this case, the logic-layer only needs to handle given data meaning Scala is assumed to be a relevant choice for the logic-layer. On the other hand, it is also mentioned that Scala has a broad support for data handling, thus making it more relevant for the data-layer. Creating functions with the same name but with different generic types, could be relevant in the context of an application programming interface (API). Since this is

(10)

9 supported by Scala and Kotlin it is concluded that using those languages are a better choice for an API compared to Jython. In this case, the logic-layer and data-layer are used as an API. Static typing is argued to be more relevant when writing a larger program that needs to be maintainable, which is in this paper assumed to be the case with the experiment. Even though the program is not relatively large it still needs to be maintainable since there are many modules with dependencies. Having many modules could make it harder finding errors, resulting in extra cost in time. Therefore, it is concluded that using Kotlin or Scala that are statically typed is better than using Jython when used together in a project.

6.3 Method

The most important flaw with the method to discuss is the fact that there is a need for more experiments. First off, there were some dependencies never tried. More specifically, Jython was never dependent on Scala, Scala on Kotlin or Kotlin on Jython. Second, the single experiment was not setup in a way allowing all the different properties shown in Appendix 1 to be tested. For example, returning null from Scala to Kotlin required an extra function to be added. Also, the fact that Scala should be better for XML-handling or data handling in general was never tested. Instead a CSV-file was imported using an external Scala-library9.

6.3.1 The Experiment – First Iteration

The solution regarding the problem with the path explained in the section 5.1 has some problems. First, having to create a symbolic link for each Jython-module requires extra work. Second, the symbolic link has to be recreated if the Jython-module inside the project is moved and the fact that the symbolic link points to an absolute path is rarely a good idea. For example, if someone else works on the project, the symbolic link must be recreated since the absolute path will most likely no longer point to the correct path.

A better solution could have been to do as in iteration 2, adding a JAR-file to the CLASSPATH, which is in this case the Scala-interface. This solution would allow Jython to import the Scala-interface and therefore eliminating the need of using a symbolic link. Though, this was not known during the time of iteration 1. Therefore, when testing if the Jython data-layer worked the code regarding the Scala-interface had to either be removed or run indirectly from the logic-layer or GUI-layer. This resulted in an unnecessary loss in time. In section 5.1 it was proposed a solution to if one would want more data about movies than just the score, it could be solved by splitting a string by the vertical bar sign. This could be problematic if for example data about a movie happens to contain the vertical bar sign, giving an incorrect result. The best way would have been to use the loosely coupled object factory from the work-around [11], that avoids having to

9https://github.com/tototoshi/scala-csv

create a factory for each Jython-class that is going to be imported. This way an object from a defined class Movie could be created, instead of storing the data in a string. 6.3.2 The Experiment – Second Iteration

Having to add the JAR-files to the CLASSPATH could not be avoided since that is the intended way as explained in the theory section. Though, it required a bit of work. First, you had to rebuild the JAR-files each time a change was made which can take quite some time. Second, the absolute path had to be manually added to the run configurations inside IntelliJ IDEA. In addition, using the absolute path is rarely a good idea as explained in 6.3.1.

6.3.3 The Experiment – Comparison of Iteration 1 and 2 Using the Java library java.time as a way to measure the run time is not optimal if you want to have a detailed and accurate result. Though, this is okay in this case since it was only interesting to see if the difference in time was noticeable. For the same reason the specification of the computer is not needed to be included. On the other hand, something that can affect the reliability of the result when measuring the performance in time is that the code was not identical enough in some cases. An example of this is the fact that the data-layer in iteration 1 returns a list of Floats while iteration 2 returns a list of Movie-objects. Another example is that different libraries for loading the CSV-file in the data-layer were used. Furthermore, the performance in time is only measured from the startup of the program and the logic-layer don’t do any work during the startup (excluding the work-around), making it hard to compare the solutions of the logic-layer.

6.3.4 References - Critique

Information about the different properties and its benefits of a programming language was often found from blog posts and other non-scientific sources. That is why many sources about the programming languages such as books are reused. The only blog post [2] including in the sources was used to show a point that Java is popular, which is not scientifically relevant for this work. Furthermore, since RQ1 is specific, it was hard finding sources to help answering RQ1. Therefore, more general sources were used that for example specified the properties and behavior of the programming languages.

7 CONCLUSION

Since the different properties and paradigms of a programming language has its pros and cons, it was important to try if it is possible using multiple programming languages together in a project. This was proven possible using Jython, Scala and Kotlin but comes with various complications that affect the performance and productivity.

(11)

10 A GUI-layer typically do not require heavy computations, however, it usually involves a relatively high amount of code and has no dependency to another modules. Jython was shown to in general be slower than Scala or Kotlin, reducing the amount of code and required using the work-around when imported. Therefore, Jython should be the best choice for problems similar to the GUI-layer. In addition, Jython does not support multiple functions with the same name but with different generic types as input parameters compared to Scala and Kotlin, which is not relevant for a GUI-layer that will not be used as an API.

Scala’s support for the functional paradigm makes it relevant for the logic-layer and Scala’s broad support for handling of data makes it also relevant for the data-layer. Though, the data handling in Scala was not tested enough to compare it to Jython or Kotlin. Therefore, it is assumed that Scala is an equally relevant choice compared to Jython and Kotlin for the data-layer. Since using Kotlin as the logic-layer compared to Scala does not have any noticeable benefits, it is concluded that Scala’s functional nature makes it a better choice when it comes to problems similar to the logic-layer. This means the problem left to solve for Kotlin is the data-layer. This could be argued to be a relevant choice since Kotlin does not allow null values, meaning that if the data would have been incorrect it is noticed early in the chain of tiers. To summarize, the best choice is Jython for the GUI-layer, Scala for the logic-layer and Kotlin for the data-layer.

8 REFERENCES

[1] Oracle, “Java,” 26 September 2010. [Online]. Available: https://web.archive.org/web/20100925204716/https://ja va.com/en/download/faq/whatis_java.xml. [Accessed 31 Januari 2019].

[2] S. Misirlakis, “Coding Dojo,” 13 December 2017.

[Online]. Available:

https://www.codingdojo.com/blog/7-most-in-demand-programming-languages-of-2018/. [Accessed 31 Januari 2019].

[3] T. Lindholm, F. Yellin, G. Bracha and A. Buckley, The Java Virtual Machine Specification, Redwood City: Oracle America, 2015, pp. 2-3.

[4] A. Sarimbekov, L. Bulej, Y. Zheng, N. Ricci and W. Binder, "Characteristics of dynamic JVM languages," in the 7th ACM workshop, Indianapolis, 2013.

[5] A. Sarimbekov, L. Stadler, L. Bulej, A. Sewe, A. Podzimek, Y. Zheng and W. Binder, "Workload characterization of JVM languages," Software: Practice and Experience, vol. 46, no. 8, pp. 1053-1089, 2016.

[6] S. Diomidis, "Choosing a Programming Language," IEEE software, vol. 23, no. 4, pp. 62-63, 2006.

[7] M. Müller, T. Müller and P. Van Roy, "Multiparadigm Programming in Oz," in Visions for the Future of Logic Programming: Laying the Foundations for a Modern Successor to Prolog, Portland, 1995.

[8] M. Odersky, P. Altherr, V. Cremet, B. Emir, S. Maneth, S. Micheloud, N. Mihaylov, M. Schinz, E. Stenman and M. Zenger, "An overview of the Scala programming language," in No. LAMP-REPORT-2004-006, Lausanne, 2004.

[9] P. Samuele and N. Rapping, Jython Essentials: rapid scripting in Java, O'Reilly Media, Inc, 2002.

[10] Panchal, K. Ronak, Patel and K. Akshay, "A comparative study: Java Vs kotlin Programming in Android," International journal of Innovative Trends in Engineering & Research, vol. 2, no. 9, pp. 4-10, 2017. [11] J. Juneau, J. Baker, V. Ng, L. Soto and F. Wierzbicki,

"Jython and Java Integration," in The definitive guide to Jython: Python for the Java platform, Apress, 2010, pp. 175-197.

[12] S. Stephen and S. Bocutiu, Programming Kotlin, Packt Publishing Ltd, 2017.

[13] JetBrains, "Calling Java code from Kotlin," JetBrains, 7 December 2018. [Online]. Available: https://kotlinlang.org/docs/reference/java-interop.html. [Accessed 5 May 2019].

[14] Oracle, "jpc.org," 28 February 2006. [Online]. Available: https://jcp.org/en/jsr/detail?id=292. [Accessed 16 April 2019].

[15] A. P. Luker, "Never Mind the Language, What About the Paradigm?," in ACM SIGCSE Bulletin, Chico, ACM, 1989, pp. 252-256.

[16] T. A. Budd and R. K. Pandey, "Never mind the paradigm, what about multiparadigm languages?," ACM SIGCSE Bulletin, vol. 27, no. 2, pp. 25-30, 1995. [17] J. C. Mitchell, "Functional and Imperative Languages,"

in Conecpts in Programming Language, Stanford, Cambridge University Press, 2003, pp. 76-82.

[18] J. C. Mitchell, "Concepts in Object-Oriented Languages," in Concepts in Programming Languages, Stanford, Cambridge University Press, 2003, pp. 277-299.

[19] M. Odersky, L. Spoon and B. Venners, Programming in Scala, Artima Inc., 2007.

(12)

9 APPENDIXES

Programming language

Property

Jython Scala Kotlin

Typing Dynamic Static Static

Compiled No Yes Yes

Pure object-oriented No Yes No

Nullable Yes Yes No [12, p. 202]

Can import Java-packages

Yes [9] Yes [19, pp. 12-13] Yes [12]

(13)

def

average(list:

Iterable

[Float]): Float = {

list.sum./(list.size)

}

def

calculateAverageScore(genre:

String

): Float = {

average(getMovies().map(movie => movie.

score

))

}

(14)
(15)

val starts = Instant.now()

// Run code to measure here

val ends = Instant.now()

println(Duration.between(starts, ends).toMillis() +

" ms"

)

(16)

Module

Iteration

Total GUI-Layer Logic-Layer Logic-Layer

Work-around

Data-Layer

Iteration 1 6000 ms 2% 80% 79-80% 18%

Iteration 2 1000 ms 20% <1% - 80%

(17)

Module Iteration

GUI-Layer Logic-Layer Data-Layer

Iteration 1 44 lines 24 lines 22 lines

Iteration 2 33 lines 21 lines 24 lines

(18)

Upphovsrätt

Detta dokument hålls tillgängligt på Internet – eller dess framtida ersättare – under 25 år från publiceringsdatum under förutsättning att inga extraordinära omständigheter uppstår.

Tillgång till dokumentet innebär tillstånd för var och en att läsa, ladda ner, skriva ut enstaka kopior för enskilt bruk och att använda det oförändrat för ickekommersiell forskning och för undervisning. Överföring av upphovsrätten vid en senare tidpunkt kan inte upphäva detta tillstånd. All annan användning av dokumentet kräver upphovsmannens medgivande. För att garantera äktheten, säkerheten och tillgängligheten finns lösningar av teknisk och administrativ art.

Upphovsmannens ideella rätt innefattar rätt att bli nämnd som upphovsman i den omfattning som god sed kräver vid användning av dokumentet på ovan beskrivna sätt samt skydd mot att dokumentet ändras eller presenteras i sådan form eller i sådant sammanhang som är kränkande för upphovsmannens litterära eller konstnärliga anseende eller egenart.

För ytterligare information om Linköping University Electronic Press se förlagets hemsida http://www.ep.liu.se/.

Copyright

The publishers will keep this document online on the Internet – or its possible replacement – for a period of 25 years starting from the date of publication barring exceptional circumstances.

The online availability of the document implies permanent permission for anyone to read, to download, or to print out single copies for his/hers own use and to use it unchanged for non-commercial research and educational purpose. Subsequent transfers of copyright cannot revoke this permission. All other uses of the document are conditional upon the consent of the copyright owner. The publisher has taken technical and administrative measures to assure authenticity, security and accessibility.

According to intellectual property law the author has the right to be mentioned when his/her work is accessed as described above and to be protected against infringement.

For additional information about the Linköping University Electronic Press and its procedures for publication and for assurance of document integrity, please refer to its www home page:

References

Related documents

46 Konkreta exempel skulle kunna vara främjandeinsatser för affärsänglar/affärsängelnätverk, skapa arenor där aktörer från utbuds- och efterfrågesidan kan mötas eller

The increasing availability of data and attention to services has increased the understanding of the contribution of services to innovation and productivity in

Object A is an example of how designing for effort in everyday products can create space to design for an stimulating environment, both in action and understanding, in an engaging and

You suspect that the icosaeder is not fair - not uniform probability for the different outcomes in a roll - and therefore want to investigate the probability p of having 9 come up in

information content, disclosure tone and likelihood of opportunistic managerial discretion impact equity investors reaction to goodwill impairment announcements?” In order to

instrument, musical role, musical function, technical challenges, solo role, piccolo duo, orchestration, instrumentation, instrumental development, timbre, sonority, Soviet

(1997) studie mellan människor med fibromyalgi och människor som ansåg sig vara friska, användes en ”bipolär adjektiv skala”. Exemplen var nöjdhet mot missnöjdhet; oberoende

The analysis is based on extractions for (spelling variants of) the noun way from the Early Modern (EEBO, PPCEME2) and Late Modern (CEAL, PPCMBE1) English periods, with a focus on