You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/11/16 11:00:49 UTC
[groovy] branch master updated: GROOVY-10361: TupleConstructor could be improved to have a smarter mode for handling default values (additional refactoring)
This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 6ef7a11 GROOVY-10361: TupleConstructor could be improved to have a smarter mode for handling default values (additional refactoring)
6ef7a11 is described below
commit 6ef7a11a0a2c53f5b3d9668f8d2ffef7e4da5ef1
Author: Paul King <pa...@asert.com.au>
AuthorDate: Tue Nov 16 21:00:36 2021 +1000
GROOVY-10361: TupleConstructor could be improved to have a smarter mode for handling default values (additional refactoring)
---
src/main/java/groovy/transform/DefaultsMode.java | 5 +++--
.../java/groovy/transform/TupleConstructor.java | 6 ++++--
.../TupleConstructorASTTransformation.java | 13 -------------
src/spec/doc/core-object-orientation.adoc | 15 ++++++++++++---
src/spec/test/objectorientation/MethodsTest.groovy | 10 ++++++++++
.../transform/TupleConstructorTransformTest.groovy | 21 ++++++++++++++++++++-
6 files changed, 49 insertions(+), 21 deletions(-)
diff --git a/src/main/java/groovy/transform/DefaultsMode.java b/src/main/java/groovy/transform/DefaultsMode.java
index c75dfa2..b2a0926 100644
--- a/src/main/java/groovy/transform/DefaultsMode.java
+++ b/src/main/java/groovy/transform/DefaultsMode.java
@@ -31,8 +31,9 @@ public enum DefaultsMode {
OFF,
/**
- * Produce multiple constructors as required to handle any parameters with explicit initial values.
- * Stops at the first parameter from the right which has no such explicit value.
+ * Produce multiple constructors as required to handle any mandatory and optional arguments.
+ * An argument is optional if the respective property/field has an explicit initial value.
+ * A property/field without an initial value is deemed mandatory.
*/
AUTO,
diff --git a/src/main/java/groovy/transform/TupleConstructor.java b/src/main/java/groovy/transform/TupleConstructor.java
index dfc3f65..1e6bf86 100644
--- a/src/main/java/groovy/transform/TupleConstructor.java
+++ b/src/main/java/groovy/transform/TupleConstructor.java
@@ -302,8 +302,10 @@ public @interface TupleConstructor {
*
* When set to {@code AUTO}, default values are catered for where explicit
* default values are given for the respective property/field.
- * Default values are processed from the right and processing stops when the
- * first property/field is found without an explicit deault value.
+ * Additional positional constructors are generated as per Groovy's normal default value processing.
+ * Properties/fields with an explicit initial value are deemed {@em optional} and may be dropped.
+ * Properties/fields with no initial value are deemed {@em mandatory} and must be supplied as an argument to the respective constructor.
+ * Optional arguments to a positional constructor are dropped from the right.
*
* When set to {@code OFF}, default values are not allowed for properties and fields.
* Only the constructor containing all arguments will be provided.
diff --git a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
index c87922c..691261a 100644
--- a/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/TupleConstructorASTTransformation.java
@@ -254,19 +254,6 @@ public class TupleConstructorASTTransformation extends AbstractASTTransformation
params.sort(includeComparator);
}
- if (defaultsMode == AUTO) {
- boolean foundNoDefault = false;
- for (int i = params.size() - 1; i >= 0; i--) {
- Parameter p = params.get(i);
- if (!p.hasInitialExpression()) {
- foundNoDefault = true;
- }
- if (foundNoDefault) {
- p.setInitialExpression(null);
- }
- }
- }
-
for (PropertyNode pNode : list) {
String name = pNode.getName();
if (shouldSkipUndefinedAware(name, excludes, includes, allNames)) continue;
diff --git a/src/spec/doc/core-object-orientation.adoc b/src/spec/doc/core-object-orientation.adoc
index 337bef0..8ff4535 100644
--- a/src/spec/doc/core-object-orientation.adoc
+++ b/src/spec/doc/core-object-orientation.adoc
@@ -419,14 +419,23 @@ Mix named and positional arguments with caution.
==== Default arguments
-Default arguments make parameters optional. If the argument is not supplied, the method assumes a default value.
+Default arguments make parameters optional.
+If the argument is not supplied, the method assumes a default value.
[source,groovy]
----
-include::../test/objectorientation/MethodsTest.groovy[tags=default_arguments ,indent=0]
+include::../test/objectorientation/MethodsTest.groovy[tags=default_arguments,indent=0]
----
-Note that no mandatory parameter can be defined after a default parameter is present, only other default parameters.
+Parameters are dropped from the right, however mandatory parameters are never dropped.
+
+[source,groovy]
+----
+include::../test/objectorientation/MethodsTest.groovy[tags=default_arguments2,indent=0]
+----
+
+The same rule applies to constructors as well as methods.
+If using `@TupleConstructor`, additional configuration options apply.
==== Varargs
diff --git a/src/spec/test/objectorientation/MethodsTest.groovy b/src/spec/test/objectorientation/MethodsTest.groovy
index 4b8cb91..3f22294 100644
--- a/src/spec/test/objectorientation/MethodsTest.groovy
+++ b/src/spec/test/objectorientation/MethodsTest.groovy
@@ -77,6 +77,16 @@ class MethodsTest extends GroovyTestCase {
assert foo('Marie').age == 1
// end::default_arguments[]
'''
+ assertScript '''
+ // tag::default_arguments2[]
+ def baz(a = 'a', int b, c = 'c', boolean d, e = 'e') { "$a $b $c $d $e" }
+
+ assert baz(42, true) == 'a 42 c true e'
+ assert baz('A', 42, true) == 'A 42 c true e'
+ assert baz('A', 42, 'C', true) == 'A 42 C true e'
+ assert baz('A', 42, 'C', true, 'E') == 'A 42 C true E'
+ // end::default_arguments2[]
+ '''
}
void testVarargs() {
diff --git a/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy b/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
index ddfca66..9976e5b 100644
--- a/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/TupleConstructorTransformTest.groovy
@@ -401,7 +401,9 @@ class TupleConstructorTransformTest extends GroovyShellTestCase {
assert C.declaredConstructors*.toString().toSet() == [
'public C(java.lang.String,int,int,java.lang.String)',
- 'public C(java.lang.String,int,int)'
+ 'public C(java.lang.String,int,int)',
+ 'public C(java.lang.String,int)',
+ 'public C(int)'
].toSet()
@TupleConstructor(defaultsMode = DefaultsMode.ON, includeFields = true)
@@ -420,5 +422,22 @@ class TupleConstructorTransformTest extends GroovyShellTestCase {
'public D()'
].toSet()
'''
+ assertScript '''
+ import groovy.transform.*
+ @Canonical(defaultsMode=DefaultsMode.AUTO)
+ class Bar {
+ String a = 'a'
+ long b
+ Integer c = 24
+ short d
+ String e = 'e'
+ }
+
+ short one = 1
+ assert new Bar(3L, one).toString() == 'Bar(a, 3, 24, 1, e)'
+ assert new Bar('A', 3L, one).toString() == 'Bar(A, 3, 24, 1, e)'
+ assert new Bar('A', 3L, 42, one).toString() == 'Bar(A, 3, 42, 1, e)'
+ assert new Bar('A', 3L, 42, one, 'E').toString() == 'Bar(A, 3, 42, 1, E)'
+ '''
}
}