[
https://issues.apache.org/jira/browse/GROOVY-12043?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18084263#comment-18084263
]
ASF GitHub Bot commented on GROOVY-12043:
-----------------------------------------
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<Integer> isEven = n -> 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<Integer,Integer> divisibleBy = (n, d) -> 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`.
> Provide curryWith helpers
> -------------------------
>
> Key: GROOVY-12043
> URL: https://issues.apache.org/jira/browse/GROOVY-12043
> Project: Groovy
> Issue Type: Sub-task
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)