Transcription

Utrecht UniversityConcepts of Programming Language Design 2021-2022INFOMCPDLanguage ReportApache Groovy Programming LanguageAuthor:Athanasios TsiamisStudent Nr. 5223652February 22, 2022a course supervised by:Prof. Dr. Gabriele Keller &Tom Smelding

Figure 1: Apache Groovy’s logoIntroductionApache Groovy is a Java-syntax-compatible object-oriented programming language for the Javaplatform. Groovy includes features found in Python, Ruby and Smalltalk, but uses syntax similarto the Java programming language making it the ideal choice for many Java programmers. Itcontains powerful features such as closures, functional programming and type inference and it issupported by the Apache Software Foundation & the Groovy community [1].A brief historyAlthough in 2003 Java dominated the market with 24% according to the TIOBE index [2], Javawasn’t the desired language for various scenarios such as scripting, applying an urgent patch orjust programming without boilerplate code. A new language was needed which should maintain aJava-like structure while also reducing the complex and often unnecessary syntax imposed by Java.James Strachan can be considered the creator and original envisionist of Groovy. He first wroteabout the development on his blog in August of 2003. He quoted “I’ve wanted to use a cooldynamically typed scripting language specifically for the Java platform for a little while.[.]I’d rathera dynamic language that builds right on top of all the groovy Java code out there & the JVM.”[3]Hence the development of this language started and in March 2004 it was formally submittedto the Java Community Process as a Java Specification Request (JSR) Nr.241 where it was unanimously accepted by ballot [4]. However, this approval was the beginning of a difficult processfor the Groovy community. For many, development took a turn towards the wrong direction andimposed a bigger workload than they were willing to do. James Strachan silently stepped downfrom his managerial position and Guillaume Laforge took his position [5]. Finally on January of2007 Groovy 1.0 was released [6] [7].In July 2012 Groovy 2.0 was released in which groovy code could be compiled statically offeringtype inference and performance near that of Java [8].As of today, Groovy 3.0.9 is the latest stable release which includes a brand new parser (codenamed Parrot) and adds, among other things, as many as 80 extension methods to existing Javaclasses. Meanwhile Groovy 4.0, which is still in beta, adds powerful switch expressions and sealedtypes which restrict other classes or interfaces interacting with them.Groovy is gaining more ground on various applications not only as a complementary languageto a Java project but also as a standalone language in a project of its own(see section 4).1

11.1Main featuresGroovy 2.0 - Static features in a dynamic languageAs mentioned before, Groovy was created to be the dynamic supplementary of Java. Developersfluent in Java could switch back and forth between the two languages seamlessly and use theappropriate type system when needed. However, as time progressed, Groovy developers fanciedGroovy’s syntax more and more and preferred to use only one language (instead of two). The issuethough was that they wanted to have a safety net for errors which only the static type check couldprovide.Groovy’s development team was struggling with this change and was hesitant to offer statictype checking. Feedback was mixed with some supporting that a shift towards static typing wouldcause Groovy to be a “failed Java 8 wannabe” [9] while others strongly supported type checkingeven if that meant that Groovy would lose some of its dynamic features [10].While this topic was still controversial, it was clear that the other languages were progressingwhile Groovy was still lacking behind; Kotlin (a static type Java like language) had been justunveiled by the JetBrains team while Java was preparing the next release [11][12]. Immediateaction was needed if Groovy would to be kept as an alive programming language.Using the right concept was no easy task for the Groovy development team. According to King(Groovy’s chair PMC) various ideas were considered for combining static and dynamic typing [5].One proposal would be gradual typing based on the work of Siek and Taha [13]. The idea behindthat would be that variables declared with a type would be statically checked while others wouldremain dynamic. According to King, while this idea was favourable to them [5], it would breakexisting codebase. Hence, the concept of gradual typing was rejected.Another option, as King suggested, would be a special switch that would set the compiler intostatic mode in which all code would be statically typed [5]. However, this option felt too crude asmany existing codebases were already making use of its dynamic features in some parts and not useit at all in others. Enforcing this binary project-wide switch did not bide well with the developers.Therefore, the compiler switches were rejected as well.The solution came eventually from a Java style annotation1 . A flexible alternative to thecompiler being in one of two modes was to indicate at the method level whether code within thatmethod was static or dynamic. A class could then be annotated (if needed) as a shorthand forannotating all methods. For example a static class could have one or more dynamic methods and adynamic class one or more static methods. Thus two new annotations were created: @TypeChecked[15] which methods binded with this would go through the Meta Object Protocol (MOP) [email protected] in which all of the MOP would be bypassed [16]. More about metaprogrammingcan be found in section 3.1.2The Groovy way - Syntax style and new featuresGroovy adds various features to the Java Virtual Machine ecosystem. Groovy’s vibrant and richopen source community has been a factory of new ideas. The following section provides a shortoverview of some important new features of the language.21 Java annotations, a form of metadata, consist of an at-sign (@) and provide data about a program that is notpart of the program itself [14].2 The list is not complete as it only contains a number of features the author found interesting. The full list offeatures can be found at https://groovy-lang.org/style-guide.html2

1.2.1Semicolons and return keywords are optionalEven though Groovy uses the JVM and Java code can be used directly into a groovy program,semicolons are optional. The same principle applies for the return keyword as well. However, forshort methods and for closures, it’s nicer to omit it for brevity. The code in section 1.2.5 providesa simple example of this.1.2.2Optional Typing - Def keywordOne of the most important keyword in the Groovy programming language is the def keyword.The def keyword is used to define an untyped variable or a function in Groovy, as it is an optionallytyped language. It can make the life of a developer easier and drive up the productivity by reducingthe need to specifically think about the variable needed. Instead they can just declare it as “def”and let the compiler infer its type. (See line 1 at section 1.2.5)1.2.3Groovy Strings (GStrings)One of the most cumbersome tasks in Java can be string manipulation in which users haveto either use external libraries or complex notation with the help of “ ” sign. Groovy reducesthis need by introducing Groovy Strings (GStrings). Gstrings represent a String which containsembedded values such as:1" hello there { user } how are you ?"which can be evaluated lazily.Advanced users can iterate over the text and values to perform special processing, such as forexecuting SQL operations, where the values can be substituted for ? and the actual value objectscan be bound to a JDBC statement3 [18]. For example:123def firstName " Thanos "def lastName " Tsiamis "sql . execute ( " INSERT INTO contactBook ( firstName , lastName ) " " values (? ,?) " , [firstName , lastName ])A more simple example of the case of GStrings can be found at section 1.2.51.2.4Switch statementGroovy’s switch statement accepts almost all types simultaneously making it a very powerfulstatement in comparison to other languages (such as C) which only accept primitive types.1.2.512345Exampledef version " 1.2 "switch ( GIT BRANCH ) {case " develop " : \\ case is of type Stringresult " dev "break3 According to IBM documentation: “Java database connectivity (JDBC) is the JavaSoft specification of astandard application programming interface (API) that allows Java programs to access database management systems.”[17]3

case [ " master " , " support / { version } " . toString () ]: \\ case is of typeArraylistresult " list "breakcase " support / { version } " : \\ case is of type GStringresult " sup "breakdefault :result " def "break}print ( " { result } " )6789101112131415162Drawbacks of GroovyEven though this report greatly praises Groovy, it is by no means a perfect language.Optional typing (i.e. def keyword), even though sometimes can be a handy feature especially whenscripting, it can make the program unnecessary difficult to understand. Strong typing makes thecontract more concrete, especially in public APIs, avoids possible passed arguments type mistakesand also helps the IDE with code completion.Additionally, progress in the Java language tends to obliterate the strong points made by Groovy.Var keyword which was introduced in Java 10 [19] started to look like the def keyword (optionaltyping) of Groovy and pattern matching for the switch keyword introduced in Java 17 [20], althoughstill more cumbersome than Groovy, may under certain circumstances reduce the need for a newlanguage.3Runtime & compile-time metaprogrammingAn in depth analysisGroovy like various others programming languages can support metaprogramming. Groovy hastwo modes of metaprogramming; runtime and compile-time metaprogramming.3.1Runtime metaprogrammingWith runtime metaprogramming it is possible to intercept, inject or even interact with othermethods at runtime. This concept (also known as monkey patch) modifies run time code but doesnot alter the original source code. Metaclasses play a key role on this process as the compiler andthe Groovy Runtime Engine interact with methods of a Metaclass class.3.1.1Expando MetaclassExpando is a special case of Metaclass that allows for dynamically adding or modifying properties, constructors or even borrowing methods from other classes by using closure syntax. It isparticularly useful for software testing and in particular simulating the behavior of a program (i.e.stubbing & mocking).However, with great power comes great responsibility. Using the expando metaclass means thatin the same JVM all objects of that class will have that method added to Metaclass which could4

maybe lead to problems. Thus, it is advised to use Categories, a feature borrowed from Objective-Cwhich addresses the issue of additional methods by limiting them in a block of code (closure). Anexample of expando metaclass can be found in appendix section A.1.3.2Compile-time metaprogrammingIn contrast to runtime metaprogramming, compile-time metaprogramming allows the code tobe generated at compile time. Those transformations are altering the Abstract Syntax Tree (AST)of a program, which is why in Groovy are called AST transformations.AST transformations are very important especially when dealing with a mix of Groovy and Javacode. For example an AST transformation can add methods to a class and be visible to Java; athing which wouldn’t be visible if runtime metaprogramming was used.Groovy comes prepacked with various AST transformations to reduce boilerplate code([email protected] ), improve coding efficiency ([email protected]) and other. Every developercan also make their own project wide or method specific AST transformation.AST transformations are of two categories; global and local. Global are applied globally on thecode wherever the transformation can apply(field, method, class etc.). Local transformations areapplied locally by using the annotation notation. The compiler will discover them and apply thetransformation on these code elements. Every developer can write their own AST (global or local)transformations. For the simplicity of this report in section A.2 a simple prepackaged example [email protected] annotation can be found which delays field instantiation until the time when that field isfirst used.4Groovy applicationsHaving set some basic Groovy rules and syntax it’s time to see where this language is being used.The following section covers a large part of a system’s development lifecycle (Development, Testing[see section 4.1] & Integration[see sections 4.2 - 4.3]) in which Groovy is the primary language.Section A contains three example applications; more specifically section A.3 contains a simpleGroovy program, which in turn is then built into bytecode by a Gradle program (which uses groovyscripting) (section A.4) and then deployed in a (hypothetical) pipeline in section A.5 which usesGroovy as well.4.1TestingGroovy has been widely used for writing test scripts in Spock and Geb. Groovy’s easy to learnsyntax and Spock’s highly expressive language makes them a top choice in the testing industry forSoftware and Quality Assurance Engineers alike. As seen in section A.3 the absence of boilerplatecode and its ”narrative” nature are one of the reasons Groovy is preferred for this job.4.2GradleGradle is an open-source build automation tool that is designed to be flexible enough to buildalmost any type of software. It is high performance, fully extensible and fully supported by numerous major IDEs such as IntelliJ IDEA, Android Studio and Eclipse. Gradle is heavily based5

upon Groovy in its core implementation and testing.4 It can be also used to either script, build theapplication or just chain tasks with the keywords shouldRunAfter and dependsOn.4.3JenkinsJenkins is a self-contained, open source automation server which can be used to automate allsorts of tasks related to building, testing, and delivering or deploying software.Groovy scripts are written in gdsl type files which are executed by the pipeline in a remoteserver such as an AWS environment. Jenkins makes also heavy use of Gradle (see section 4.2) tocombine the whole pipeline into one seamless process.5ConclusionGroovy was created as a Java supplementary and as time progressed it is considered a greatJava alternative. It vastly improves various features found in many object oriented languages whileit adds many more due to its vibrant community of developers. Meanwhile, its applications invarious parts of the product’s development cycle make it the ideal choice for many.ACoding ExamplesA.1Runtime metaprogramming ExampleThe following example is taken from ”Groovy in Action” Konig et al [21].1234567class Spy {static {def mc new E x p a n d o M e t a C l a s s ( Spy , false , true )mc . initialize ()Spy . metaClass mc}String name " James "891011121314151617181920212223242526void methodMissing ( String name , args ) {if ( name . startsWith ( ’ changeNameTo ’) ) {println " Adding method name "String newName name . substring (12)def newMethod { delegate . name newName }Spy . metaClass . " name " newMethodnewMethod ()} else {throw new M i s s i n g M e t h o d E x c e p t i o n ( name , this . class , args )}}static void main ( String [] args ) {def spy new Spy ()assert " James " spy . namespy . c h a n g e N a m e T o A u s t i n ()assert " Austin " spy . namespy . c h a n g e N a m e T o M a x w e l l ()assert " Maxwell " spy . name4 Moreinformation about the source code can be found at Gradle’s repository hosted at Github gradle/gradle6

spy . c h a n g e N a m e T o A u s t i n ()27}2829}The output of this program if we use main as an entry point is:12Adding method c h a n g e N a m e T o A u s t i nAdding method c h a n g e N a m e T o M a x w e l lNotice that even though there are two calls spy.changeNameToAustin() there is only one print tothe console as the second one was already registered as a method and therefore methodMissing wasnot used.A.2Compile time metaprogramming ExampleThe following example is taken from ”Groovy in Action” Konig et al [21] as well. It shows howan expensive resource (e.g. database) can be lazily evaluated ([email protected]) to save costs.123456789101112131415161718192021class Resource {private static alive 0private static used 0Resource () { alive }def use () { used }static stats () { " alive alive , used used " }}class ResourceMain {def res1 new Resource ()@Lazy res2 new Resource ()@Lazy static res3 { new Resource () }()@Lazy ( soft true ) volatile Resource res4}new ResourceMain () . with {assert Resource . stats () ’1 alive , 0 used ’res2 . use ()res3 . use ()res4 . use ()assert Resource . stats () ’4 alive , 3 used ’assert res4 instanceof Resource}A.3123Groovy test fileimport spock . lang . Specificationclass Us er Jo u rn ey Sp e c extends Specification {ArrayList shoppingCart []45678def setup () { \\ setup runs automatically before every testprintln ( " Setting up test data . " )assert shoppingCart . empty \\ the assert keyword could be omitted}910111213def cleanup () { \\ cleanup runs automatically after every testprint ( " Deleting everything from the basket " )shoppingCart . clear ()}147

def " Users buys groceries from the website " () {when : " User logs in the website "userLogsIn () \\ an external method that logs in the user into the website15161718and : " Adds someshoppingCart shoppingCart shoppingCart 19202122products to the basket "" banana "" apple "" orange "23then : " Cart is not empty "shoppingCart . size () 3242526when : " User decides to remove the apple from his cart "shoppingCart - " apple "272829then : " Cart does not contain apple but still has the other fruits "! shoppingCart . contains ( " apple " )shoppingCart . size () 2303132}3334}A.41Gradle file[.] \\ gradle specific commands are omitted for brevity234567891011121314tasks . register ( ’ t e s t S u i t e S i z e V a l i d a t i o n ’) {doLast {print ( " Validating that no extra test classes were added by a developer " )def path " .\\ GroovyTesting \\ src \\ test \\ groovy \\ "def list []def dir new File ( new File ( path ) . ge tA b so lu te P at h () )dir . ea ch F il eR ec u rs e { file - list file}assert list . size () 1}}A.51Jenkinsfilepipeline {23agent any45678triggers {cron ( ’H */8 * * * ’) // regular buildspollSCM ( ’* * * * * ’) // polling for changes , here once a minute}910111213stages {stage ( ’ Checkout ’) {steps { // Checking out the repocheckout changelog : true , poll : true , scm : [ class : ’ GitSCM ’ ,branches : [[ name : ’ */ master ’]] , browser : [ class : ’ BitbucketWeb ’ , repoUrl : ’https :// web . com / blah ’] , d o G e n e r a t e S u b m o d u l e C o n f i g u r a t i o n s : false , extensions :8

[] , submoduleCfg : [] , u s e r R e m o t e C o n f i g s : [[ credentialsId : ’ git ’ , url : ’ ssh ://[email protected] . giturl . com / test / test . git ’ ]]]}}stage ( " Validating that the number of tests is correct " ) {steps {script {try {print ( " Gradle task starting now . " )sh " ./ gradlew -q t e s t S u i t e S i z e V a l i d a t i o n "} finally {print ( " Task finished ! " )}}}}141516171819202122232425262728stage ( " Building the application " ) {steps {script {try {print ( " Gradle task starting now . " )sh ’ ./ gradlew -q build ’ // run a gradle task} finally {print ( " Task finished ! " )}}}}293031323334353637383940}stage ( " Notify in Slack " ) {buildStatus resultdef subject " { buildStatus }: Job ’ { env . JOB NAME } [ { env . BUILD NUMBER }] ’ "def summary " { subject } ( { env . BUILD URL }) "if ( result " FAIL " ) {color " RED "colorCode " # FF0000 "slackSend ( color : colorCode , message : summary )error ( " Job has failed " )} else {color " GREEN "colorCode " #00 FF00 "slackSend ( color : colorCode , message : summary ] The Apache Groovy programming language. url: https://groovy-lang.org/.[2] TIOBE index. url: https://www.tiobe.com/tiobe-index/.[3]James Strachan. Groovy - the birth of a new dynamic language for the Java platform. 2003.url: https : / / web . archive . org / web / 20030901064404 / http : / / radio . weblogs . com /0112098/2003/08/29.htm.9

[4] JSR 241: The Groovy Programming Language. url: https://jcp.org/en/jsr/detail?id 241.[5]Paul King. “A History of the Groovy Programming Language”. In: Proc. ACM Program. Lang.4.HOPL (June 2020). doi: 10.1145/3386326. url: https://doi.org/10.1145/3386326.[6]Guillaume Laforge. Groovy 1.0 is there! url: eremy Rayner. Groovy 1.0 released! url: http : / / javanicus . com / blog2 / items / 204 index.html.[8]Oliver Plohmann. Groovy 2.0 Performance compared to Java. url: performance-compared-to-java.html.[9]Russel Winder. static compilation for Groovy. url: https : / / markmail . org / message /g627wfm5au3emher.[10]Endre Stølsvik. Consider statically typed/compiled as default for Groovy 3.0. url: https aul Krill. JetBrains readies JVM-based language. url: /www.infoworld.com/article/2622405/jetbrains- readiesjvm-based-language.html.[12] JSR 336: JavaTM SE 7 Release Contents. url: https://jcp.org/en/jsr/detail?id 336.[13]Jeremy Siek and Walid Taha. “Gradual Typing for Objects”. In: Aug. 2007, pp. 2–27. isbn:978-3-540-73588-5. doi: 10.1007/978-3-540-73589-2 2.[14] The Java Tutorials Lesson: Annotations. url: https : / / docs . oracle . com / javase /tutorial/java/annotations/.[15] GEP-8. url: https://groovy.apache.org/wiki/GEP-8.html.[16] GEP 10. url: https://groovy.apache.org/wiki/GEP-10.html.[17] What is JDBC? url: ?topic started-what-is-jdbc.[18]James Strachan. Class GString. url: y/lang/GString.html.[19] JDK 10 Release Notes. url: relnote-issues.html.[20] JDK 17 Release Notes. url: k Konig et al. Groovy in Action. 2nd ed. Manning, 2015. isbn: 9781935182443; 1935182447.10

Apache Groovy is a Java-syntax-compatible object-oriented programming language for the Java platform. Groovy includes features found in Python, Ruby and Smalltalk, but uses syntax similar to the Java programming language making it the ideal choice for many Java programmers. It contains powerful features such as closures, functional programming .