Copilot commented on code in PR #2569:
URL: https://github.com/apache/groovy/pull/2569#discussion_r3322454065


##########
src/main/java/org/apache/groovy/util/Closures.java:
##########
@@ -0,0 +1,237 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.util;
+
+import groovy.lang.Closure;
+
+import java.io.Serial;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Helpers that return hybrid one-argument functions which are both
+ * {@link Closure} and the appropriate {@link java.util.function} SAM
+ * ({@link Predicate}, {@link Function} or {@link Consumer}).
+ * <p>
+ * For variants whose results are only the SAM type, see {@link Lambdas}.
+ *
+ * @since 6.0.0
+ */
+public class Closures {
+

Review Comment:
   This utility class lacks a private no-arg constructor to prevent 
instantiation. Other utility classes in `org.apache.groovy.util` consistently 
declare one (e.g. `Arrays.java:62`, `BeanUtils.java:72-73`, `Maps.java:6121`). 
The static factory entry points and nested hybrid classes suggest `Closures` is 
not meant to be instantiated.



##########
src/main/java/org/apache/groovy/util/Lambdas.java:
##########
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.util;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Helpers that return {@link java.util.function} types.
+ * <p>
+ * For variants whose results are also {@link groovy.lang.Closure}
+ * instances, see {@link Closures}.
+ *
+ * @since 6.0.0
+ */
+public class Lambdas {
+

Review Comment:
   This new utility class lacks a private no-arg constructor. Other utility 
classes in `org.apache.groovy.util` consistently declare a private constructor 
to prevent instantiation (e.g. `Arrays.java:62`, `BeanUtils.java:72-73`, 
`Maps.java:6121`). Since `Lambdas` only exposes static helpers, please add a 
private constructor for consistency.



##########
src/main/java/org/apache/groovy/util/Closures.java:
##########
@@ -0,0 +1,237 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.groovy.util;
+
+import groovy.lang.Closure;
+
+import java.io.Serial;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Helpers that return hybrid one-argument functions which are both
+ * {@link Closure} and the appropriate {@link java.util.function} SAM
+ * ({@link Predicate}, {@link Function} or {@link Consumer}).
+ * <p>
+ * For variants whose results are only the SAM type, see {@link Lambdas}.
+ *
+ * @since 6.0.0
+ */
+public class Closures {
+
+    /**
+     * Lifts a {@link Predicate} into a hybrid that is also a
+     * {@link Closure}. If {@code p} is already a {@link PredicateClosure}
+     * it is returned unchanged.
+     * <pre class="language-groovy">
+     * Predicate&lt;Integer&gt; isEven = n -&gt; n % 2 == 0
+     * assert [1, 2, 3, 4].findAll(Closures.from(isEven)) == [2, 4]
+     * </pre>
+     *
+     * @since 6.0.0
+     */
+    public static <T> PredicateClosure<T> from(Predicate<T> p) {
+        if (p instanceof PredicateClosure) {
+            @SuppressWarnings("unchecked")
+            PredicateClosure<T> pc = (PredicateClosure<T>) p;
+            return pc;
+        }
+        return new PredicateClosure<>(p);
+    }
+
+    /**
+     * Lifts a {@link Function} into a hybrid that is also a
+     * {@link Closure}. If {@code f} is already a {@link FunctionClosure}
+     * it is returned unchanged.
+     *
+     * @since 6.0.0
+     */
+    public static <T, R> FunctionClosure<T, R> from(Function<T, R> f) {
+        if (f instanceof FunctionClosure) {
+            @SuppressWarnings("unchecked")
+            FunctionClosure<T, R> fc = (FunctionClosure<T, R>) f;
+            return fc;
+        }
+        return new FunctionClosure<>(f);
+    }
+
+    /**
+     * Lifts a {@link Consumer} into a hybrid that is also a
+     * {@link Closure}. If {@code c} is already a {@link ConsumerClosure}
+     * it is returned unchanged.
+     *
+     * @since 6.0.0
+     */
+    public static <T> ConsumerClosure<T> from(Consumer<T> c) {
+        if (c instanceof ConsumerClosure) {
+            @SuppressWarnings("unchecked")
+            ConsumerClosure<T> cc = (ConsumerClosure<T>) c;
+            return cc;
+        }
+        return new ConsumerClosure<>(c);
+    }
+
+    /**
+     * Right-partials a {@link BiPredicate} and lifts the result into a
+     * hybrid usable as both {@link Closure} and {@link Predicate}.
+     * Equivalent to {@code from(Lambdas.curryWith(bp, p))}.
+     * <pre class="language-groovy">
+     * BiPredicate&lt;Integer,Integer&gt; divisibleBy = (n, d) -&gt; n % d == 0
+     * assert [1, 2, 3, 4, 5].findAll(curryWith(divisibleBy, 2)) == [2, 4]
+     * </pre>
+     *
+     * @since 6.0.0
+     */
+    public static <T, P> PredicateClosure<T> curryWith(BiPredicate<? super T, 
? super P> bp, P p) {
+        return from(Lambdas.curryWith(bp, p));
+    }
+
+    /**
+     * Right-partials a {@link BiFunction} and lifts the result into a
+     * hybrid usable as both {@link Closure} and {@link Function}.
+     * Equivalent to {@code from(Lambdas.curryWith(bf, p))}.
+     *
+     * @since 6.0.0
+     */
+    public static <T, P, R> FunctionClosure<T, R> curryWith(BiFunction<? super 
T, ? super P, ? extends R> bf, P p) {
+        return from(Lambdas.curryWith(bf, p));
+    }
+
+    /**
+     * Right-partials a {@link BiConsumer} and lifts the result into a
+     * hybrid usable as both {@link Closure} and {@link Consumer}.
+     * Equivalent to {@code from(Lambdas.curryWith(bc, p))}.
+     *
+     * @since 6.0.0
+     */
+    public static <T, P> ConsumerClosure<T> curryWith(BiConsumer<? super T, ? 
super P> bc, P p) {
+        return from(Lambdas.curryWith(bc, p));
+    }
+
+    /**
+     * Hybrid one-argument function that is both a {@link Closure} and a
+     * {@link Predicate}.
+     *
+     * @since 6.0.0
+     */
+    public static class PredicateClosure<T> extends Closure<Boolean> 
implements Predicate<T> {
+        @Serial private static final long serialVersionUID = 1L;
+        private final Predicate<T> delegate;
+
+        PredicateClosure(Predicate<T> delegate) {
+            super(null, null);
+            this.delegate = delegate;
+            this.maximumNumberOfParameters = 1;
+            this.parameterTypes = new Class<?>[]{Object.class};
+        }
+
+        @Override
+        public boolean test(T t) {
+            return delegate.test(t);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public Boolean call(Object arg) {
+            return test((T) arg);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public Boolean call(Object... args) {
+            return test((T) args[0]);
+        }

Review Comment:
   `call(Object... args)` will throw an unhelpful 
`ArrayIndexOutOfBoundsException` (and `NullPointerException` if `args` is null) 
when called with the wrong arity, rather than the more informative 
`MissingMethodException`/`IllegalArgumentException` users would expect from a 
`Closure` call. Consider validating arity (e.g. `if (args == null || 
args.length != 1) throw new IllegalArgumentException(...)`) before indexing, in 
`PredicateClosure`, `FunctionClosure`, and `ConsumerClosure`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to