On 30.12.23 19:17, Agile Developer wrote:
Hi,
I was a 4 years user of Grails/Groovy (last year mostly Python). With
the general trend of people moving to static languages, is there any
reason that Groovy needs to stay dynamic?
I see Python having the mypy approach, I see gradle moving to Kotlin and
FE mostly on Typescript.
mypy is optional typing. You have that in Groovy on two levels as well.
Firstly you can use types in method signatures and for variables. Those
will cause runtime errors if not conforming to. Then there is
@TypeChecked allowing for compile time type checks. And @CompileStatic
for more java-like compilation, actually having different semantics than
normal Groovy.
You say you see Gradle moving to Kotlin... well.. the idea was imho to
let the Kotling people deliver a new DSL for Gradle. But an incompatible
DSL would be bad for Gradle. So Kotlin so far did not much more than
produce a slightly different DSL, making nothing much easier and some
things more complicated. That the Gradle DSL has some design mistakes in
it, is not because of Groovy, it is from inexperience.
I understand that the @CompileStatic is the supported method, but having
true static typing (with the Script-Like enhancements other Languages
added, would be beneficial).
How is @CompileStatic not true static typing? You have to explain that I
think. Also what do you mean with Script-Like enhancements other
Languages added? Because those reach from executing directly from source
to not having the usual wrapper constructs.
Is there still a reason to keep it dynamic? What is the benefit?
Well, that depends on the features you want to keep.
(1) extension methods
In Groovy you can add methods to classes without extending the class by
defining and registering methods in a certain format. We use this
mechanism a lot in Groovy to for example define "asBoolean" or "each".
Now given a small program like this:
void m(Object x) {
x.foo()
}
For static compilation we use the static defined type of x to see if it
has a foo() method defined. This includes extension methods. This we can
actually add a foo() method to Object or even null. This would, so far,
work with static compilation as well, it just has to dispatch to the
extension method instead of a method defined on x. But what is if x is
of type X and actually has a foo() method? Well, since this is static
compilation and we can only choose statically and we know of x only that
it is Object we have almost no other choice but to call the extension
method instead of X#foo(). So either we do not choose the method at
compile time or we call the "wrong" method. Kotlin for example has
extensions, that have the same problem, which is why they state that the
method will be selected statically, thus Object#foo() must exist for
this compile and it does not matter what x really is at runtime
Object#foo() would be called.
(2) builder
an example for a very very simple html builder in Groovy would be for
example:
https://gwc-experiment.appspot.com/?gist=860a1e156d5eca5ddd846260faf2d7fa
The usage
new SimpleBuilder().html {
head {
title ("Simple Groovy HTML builder")
body {
h1 ("Simple Groovy HTML builder")
p ("this format can be used as an alternative markup to HTML")
a(href: "http://groovy-lang.org","Groovy")
p {
_ ("This is some")
b ("mixed")
_ "text. For more see the "
a(href:"http://groovy-lang.org","Groovy")
_ "project"
}
p {
_ "some text"
ul {
5.times { i -> li("${i}*2 = ${i*2}" )}
}
}
}
}
}
is very similar to the usage for example in Kotlin (from
https://github.com/Kotlin/kotlin-by-example/blob/0e614d4431092ad6d1ffb0f0e3510db9e9b5eb48/examples/09_Kotlin_JS/06_HtmlBuilder.md?plain=1#L12):
html {
head {
title { +"HTML encoding with Kotlin" }
}
body {
h1 { +"HTML encoding with Kotlin" }
p { +"this format can be used as an alternative markup to HTML" }
a(href = "http://kotlinlang.org") { +"Kotlin" }
p {
+"This is some"
b { +"mixed" }
+"text. For more see the"
a(href = "http://kotlinlang.org") {
+"Kotlin"
}
+"project"
}
p {
+"some text"
ul {
for (i in 1..5)
li { +"${i}*2 = ${i*2}" }
}
}
}
}
and of course the Kotlin version automatically disallows variants the
Groovy version would still allow. And you buy that by defining around 15
helper classes in 100 lines, while the Groovy version was written in
like 10 Minutes and requires only one quarter the amount of lines. So
yes, type safe builder are possible, even in Groovy actually, but it
comes with a price in implementation cost. Point being, that the Groovy
variant here works only because of the dynamic invokeMethod logic. Could
I statically compile to invokeMethod? yes, sure. But your method calls
then loose type safety, or not? What's the purpose then? Now assume I
want to add a new tag ol. What do I have to change in my Groovy code?
Nothing. What do I have to change in the Kotlin variant? I have to make
a new OL class and I have to change the BodyTag class. Sure, that is not
much, but more than nothing. For me more important is to have the logic
in one place
(3) multi methods / double dispatch
That makes the third point in the department method dispatch actually.
anyway..
Let us assume I have
void m(Foo foo) {
foo.bar("1")
}
Let us assume there is a Foo#foo(Object) method and a Foo2#bar(String)
method, where Foo2 extends Foo. Now in m a Java compiler knows about
Foo, but not Foo2 and will create a a dispatch to bar(Object) instead of
bar(String) if foo is a Foo2. In normal Groovy this will always call the
bar(String) method if foo is a Foo2 and bar(Object) if this is a Foo.
For static compilation I could have also written:
void m(Foo foo) {
foo.bar("1")
}
void m(Foo2 foo) {
foo.bar("1")
}
and now if m(Foo2) is called it will call Foo2#bar(String), and if
m(Foo) is called Foo#bar(Object) will be called - always. But then, who
does ensure the call to m is done "right"? Not the static compiler. Of
course you can now go with the visitor pattern to solve this and have
total overkill. Or you add a dynamic element.
(4) meta class system
Well.. actually I think the mail is already too long...
https://groovy-lang.org/metaprogramming.html#_metaclasses is of course a
reference.
bye Jochen