Function parameter order

Brian Goetz brian.goetz at oracle.com
Thu Nov 8 07:47:19 PST 2012


Let me step back and ask about your goal here.

Doug has laid out an argument ("the tyranny of function names") that we 
will eventually want the full combinatorial explosion, expressed in a 
mechanizable manner.

It is also pretty clear that any such names are going to be pretty ugly, 
so we'd rather not make users deal with them directly if avoidable.  The 
hope is that the two are ultimately reconcileable.

In the review request (which, btw, we've exceeded our time box on), Mike 
stated: "Doug has also suggested we have some sort of regularized, 
low-level naming scheme.  There's nothing in this bunch that is 
inconsistent with that; if we had such a thing, the nominal SAMs here 
could easily implement the horribly named low-level versions.  We're 
still thinking about how that might fit in, so while that's not directly 
reflected here, it hasn't been forgotten."

The scheme you propose seems to try to play on both sides of "have some 
nice simple names" and "have a fully regularized scheme".  What's the 
goal here?  It is to replace all the specializations, or is it an 
alternate casting of Doug's scheme that incorporates the 
Predicate/Function names?

On 11/7/2012 12:18 PM, Raab, Donald wrote:
> From: lambda-libs-spec-experts-bounces at openjdk.java.net [mailto:lambda-libs-spec-experts-bounces at openjdk.java.net] On Behalf Of Brian Goetz
> Sent: Wednesday, November 07, 2012 11:25 AM
>
> Fair objection.  But I'm not hearing anyone proposing a consistent and simple way to interpret the relationship between IntFoo<T> and Foo<T,U>; all I'm hearing is complaining that they don't like the proposed solution.
>
> -------------------
>
> Ok, so I spent a few hours the past 3 days trying different things out so I could see if could come up with an alternative proposal I would like better than the one we already use today in GS Collections.  I borrowed some of Doug's ideas from Op in extra166y and the names from GS Collections.
>
> Here is a test I wrote that shows all of the useful combinations I can think of in a few hours time (there are more of course).  It should show how these things will look better than me trying to use some formal specification.  I know some folks hate numeric arity, but I think it is a form of useful compression (how many Objects are in ObjectObjectObjectObjectObject or TTTTT vs. just saying Object5 or T5).  If you don't like "T" here please replace it with "Object" or your favorite generified type name.
>
> I've included 3 tests below.  One for Procedure, Function and IntFunction.  Predicate will be like Procedure (only one class) so I didn't include it, although technically, it could be handled with a BooleanFunction.  I prefer Predicate, but I wonder whether both BooleanFunction and Predicate are useful.
>
> I will assume if you can't reason about it without asking lots of questions, then it is not a good proposal.  Return type is the last parameter in the list of generic types in the case of Function, so hopefully that explains one little thing that might be hard to figure out with all Strings in the examples.
>
> I will paste the source for the interfaces themselves if anyone wants to see it.
>
> ----------------------
>
> package blocks;
>
> import junit.framework.Assert;
> import org.junit.Test;
>
> public class LambdaTest
> {
>      @Test
>      public void procedures()
>      {
>          Procedure empty = () -> {System.out.println("apply");};
>
>          Procedure.T<String> a = aString -> {System.out.println("apply" + aString);};
>          Procedure.T2<String, String> b = (aString1, aString2) -> {System.out.println("apply" + aString1 + aString2);};
>          Procedure.T3<String, String, String> c = (aString1, aString2, aString3) -> {System.out.println("apply" + aString1 + aString2 + aString3);};
>
>          Procedure.TInt<String> d = (aString, anInt) -> {System.out.println("apply" + aString + anInt);};
>          Procedure.TFloat<String> e = (aString, aFloat) -> {System.out.println("apply" + aString + aFloat);};
>          Procedure.TLong<String> f = (aString, aLong) -> {System.out.println("apply" + aString + aLong);};
>          Procedure.TDouble<String> g = (aString, aDouble) -> {System.out.println("apply" + aString + aDouble);};
>
>          Procedure.Int h = anInt -> {System.out.println("apply" + anInt);};
>          Procedure.Int2 i = (anInt1, anInt2) -> {System.out.println("apply" + anInt1 + anInt2);};
>          Procedure.IntT<String> j = (anInt, aString) -> {System.out.println("apply" + anInt + aString);};
>
>          Procedure.Float k = aFloat -> {System.out.println("apply" + aFloat);};
>          Procedure.Float2 l = (aFloat1, aFloat2) -> {System.out.println("apply" + aFloat1 + aFloat2);};
>          Procedure.FloatT<String> m = (aFloat, aString) -> {System.out.println("apply" + aFloat + aString);};
>
>          Procedure.Double n = aDouble -> {System.out.println("apply" + aDouble);};
>          Procedure.Double2 o = (aDouble1, aDouble2) -> {System.out.println("apply" + aDouble1 + aDouble2);};
>          Procedure.DoubleT<String> p = (aDouble, aString) -> {System.out.println("apply" + aDouble + aString);};
>
>          Procedure.Long q = aLong -> {System.out.println("apply" + aLong);};
>          Procedure.Long2 r = (aLong1, aLong2) -> {System.out.println("apply" + aLong1 + aLong2);};
>          Procedure.LongT<String> s = (aLong, aString) -> {System.out.println("apply" + aLong + aString);};
>      }
>
>      @Test
>      public void objectFunctions()
>      {
>          Function<String> empty = () -> "apply";
>          Assert.assertEquals("apply", empty.apply());
>
>          Function.T<String, String> a = aString -> "apply" + aString;
>          Assert.assertEquals("apply1", a.apply("1"));
>
>          Function.T2<String, String, String> b = (aString1, aString2) -> "apply" + aString1 + aString2;
>          Assert.assertEquals("apply12", b.apply("1", "2"));
>
>          Function.T3<String, String, String, String> c = (aString1, aString2, aString3) -> "apply" + aString1 + aString2 + aString3;
>          Assert.assertEquals("apply123", c.apply("1", "2", "3"));
>
>          Function.TInt<String, String> d = (aString, anInt) -> "apply" + aString + anInt;
>          Assert.assertEquals("apply12", d.apply("1", 2));
>
>          Function.TFloat<String, String> e = (aString, aFloat) -> "apply" + aString + aFloat;
>          Assert.assertEquals("apply12.0", e.apply("1", 2.0f));
>
>          Function.TLong<String, String> f = (aString, aLong) -> "apply" + aString + aLong;
>          Assert.assertEquals("apply12", f.apply("1", 2L));
>
>          Function.TDouble<String, String> g = (aString, aDouble) -> "apply" + aString + aDouble;
>          Assert.assertEquals("apply12.0", g.apply("1", 2.0d));
>
>          Function.Int<String> h = anInt -> "apply" + anInt;
>          Assert.assertEquals("apply1", h.apply(1));
>
>          Function.Int2<String> i = (anInt1, anInt2) -> "apply" + anInt1 + anInt2;
>          Assert.assertEquals("apply12", i.apply(1, 2));
>
>          Function.IntT<String, String> j = (anInt, aString) -> "apply" + anInt + aString;
>          Assert.assertEquals("apply12", j.apply(1, "2"));
>
>          Function.Float<String> k = aFloat -> "apply" + aFloat;
>          Assert.assertEquals("apply1.0", k.apply(1.0f));
>
>          Function.Float2<String> l = (aFloat1, aFloat2) -> "apply" + aFloat1 + aFloat2;
>          Assert.assertEquals("apply1.02.0", l.apply(1.0f, 2.0f));
>
>          Function.FloatT<String, String> m = (aFloat, aString) -> "apply" + aFloat + aString;
>          Assert.assertEquals("apply1.02", m.apply(1.0f, "2"));
>
>          Function.Double<String> n = aDouble -> "apply" + aDouble;
>          Assert.assertEquals("apply1.0", n.apply(1.0d));
>
>          Function.Double2<String> o = (aDouble1, aDouble2) -> "apply" + aDouble1 + aDouble2;
>          Assert.assertEquals("apply1.02.0", o.apply(1.0d, 2.0d));
>
>          Function.DoubleT<String, String> p = (aDouble, aString) -> "apply" + aDouble + aString;
>          Assert.assertEquals("apply1.02", p.apply(1.0d, "2"));
>
>          Function.Long<String> q = aLong -> "apply" + aLong;
>          Assert.assertEquals("apply1", q.apply(1L));
>
>          Function.Long2<String> r = (aLong1, aLong2) -> "apply" + aLong1 + aLong2;
>          Assert.assertEquals("apply12", r.apply(1L, 2L));
>
>          Function.LongT<String, String> s =(aLong, aString) -> "apply" + aLong + aString;
>          Assert.assertEquals("apply12", s.apply(1L, "2"));
>      }
>
>      @Test
>      public void intFunctions()
>      {
>          IntFunction empty = () -> 0;
>          Assert.assertEquals(0, empty.apply());
>
>          IntFunction.T<String> a = aString -> Integer.parseInt(aString);
>          Assert.assertEquals(1, a.apply("1"));
>          IntFunction.T2<String, String> b = (aString1, aString2) -> Integer.parseInt(aString1) + Integer.parseInt(aString2);
>          Assert.assertEquals(3, b.apply("1", "2"));
>          IntFunction.T3<String, String, String> c = (aString1, aString2, aString3) -> Integer.parseInt(aString1) + Integer.parseInt(aString2) + Integer.parseInt(aString3);
>          Assert.assertEquals(6, c.apply("1", "2", "3"));
>
>          IntFunction.TInt<String> d = (aString, anInt) -> Integer.parseInt(aString) + anInt;
>          Assert.assertEquals(3, d.apply("1", 2));
>          IntFunction.TFloat<String> e = (aString, aFloat) -> Integer.parseInt(aString) + (int)aFloat;
>          Assert.assertEquals(3, e.apply("1", 2.0f));
>          IntFunction.TLong<String> f = (aString, aLong) -> Integer.parseInt(aString) + (int)aLong;
>          Assert.assertEquals(3, f.apply("1", 2L));
>          IntFunction.TDouble<String> g = (aString, aDouble) -> Integer.parseInt(aString) + (int)aDouble;
>          Assert.assertEquals(3, g.apply("1", 2.0d));
>
>          IntFunction.Int h = anInt -> anInt;
>          Assert.assertEquals(1, h.apply(1));
>          IntFunction.Int2 i = (anInt1, anInt2) -> anInt1 + anInt2;
>          Assert.assertEquals(3, i.apply(1, 2));
>          IntFunction.IntT<String> j = (anInt, aString) -> anInt + Integer.parseInt(aString);
>          Assert.assertEquals(3, j.apply(1, "2"));
>
>          IntFunction.Float k = aFloat -> (int)aFloat;
>          Assert.assertEquals(1, k.apply(1.0f));
>          IntFunction.Float2 l = (aFloat1, aFloat2) -> (int)aFloat1 + (int)aFloat2;
>          Assert.assertEquals(3, l.apply(1.0f, 2.0f));
>          IntFunction.FloatT<String> m = (aFloat, aString) -> (int)aFloat + Integer.parseInt(aString);
>          Assert.assertEquals(3, m.apply(1.0f, "2"));
>
>          IntFunction.Double n = aDouble -> (int)aDouble;
>          Assert.assertEquals(1, n.apply(1.0d));
>          IntFunction.Double2 o = (aDouble1, aDouble2) -> (int)aDouble1 + (int)aDouble2;
>          Assert.assertEquals(3, o.apply(1.0d, 2.0d));
>          IntFunction.DoubleT<String> p = (aDouble, aString) -> (int)aDouble + Integer.parseInt(aString);
>          Assert.assertEquals(3, p.apply(1.0d, "2"));
>
>          IntFunction.Long q = aLong -> (int)aLong;
>          Assert.assertEquals(1, q.apply(1L));
>          IntFunction.Long2 r = (aLong1, aLong2) -> (int)aLong1 + (int)aLong2;
>          Assert.assertEquals(3, r.apply(1L, 2L));
>          IntFunction.LongT<String> s =(aLong, aString) -> (int)aLong + Integer.parseInt(aString);
>          Assert.assertEquals(3, s.apply(1L, "2"));
>      }
> }
>
>
>
>
>


More information about the lambda-libs-spec-observers mailing list