From scolebourne at joda.org Wed Jan 2 15:21:41 2013 From: scolebourne at joda.org (Stephen Colebourne) Date: Wed, 2 Jan 2013 23:21:41 +0000 Subject: Request for review: proposal for @FunctionalInterface checking In-Reply-To: <50E486C9.6080107@oracle.com> References: <50DDFAC7.4030206@oracle.com> <50E486C9.6080107@oracle.com> Message-ID: Putting my user hat on and imagining writing framework-type code using functional interfaces, I think that the annotation is a good idea. However, encoding the signature seems a little unnecessary when standard Java reflection of the SAM method gets you that information. The problem is finding that SAM method to perform reflection on. A simple loop of all methods to find the only non-default one isn't enough. You'll also have to filter methods on Object and handle multiple superclass hierarchies. Basically, implement the full JLS search. Very non-ideal. In an ideal world, what I want is this: @FunctionalInterface(method=Predicate#test) interface Predicate { ... } where Predicate#test is a reference returning a reflection Method object (as that can be introspected further, but Predicate::test cannot). This approach would also deal with interface hierarchies (so that the sub-interface can specify which super-interface it intends to have provide the SAM). The next best would seem to be: @FunctionalInterface(samClass=Predicate.class, samMethod="test") interface Predicate { ... } Specifying the signature of the SAM seems like the wrong this to be chasing here. As a side note, an alternative approach would be reflection helper methods: public static Method isFunctionalInterface(Class interfce) public static Method findFunctionalInterfaceMethod(Class interfce) This may actually be more broadly applicable. Stephen On 2 January 2013 19:13, Brian Goetz wrote: > In Doug's "tyranny of function names", there was an appeal for a known, > regularized naming convention: > >> Using anything other than a known regularized naming scheme >> in libraries will make it impossible to ever take advantage of >> language-based function type support. > > > Perhaps @FunctionalInterface can be extended to provide this. Instead of > just > > @FunctionalInterface > interface Predicate { ... } > > the annotation could capture the parameter and return types as well: > > @FunctionalInterface(return = boolean.class, > params = { Object.class }) > interface Predicate { ... } > > (or better, some scheme that lets us encode generic signatures rather than > erased ones). > > Then we're making a clear statement that "Predicate is a functional > interface with type signature T->boolean", which would open the door to > future loosenings in a less ad-hoc way? > > Doug, does this help at all? > > > On 12/28/2012 3:02 PM, Joe Darcy wrote: >> >> Hello, >> >> We've had some discussions internally at Oracle about adding a >> FunctionalInterface annotation type to the platform and we'd now like to >> get the expert group's evaluation and feedback on the proposal. >> >> Just as the java.lang.Override annotation type allows compile-time >> checking of programmer intent to override a method, the goal for the >> FunctionalInterface annotation type is to enable analogous compile-time >> checking of whether or not an interface type is functional. Draft >> specification: >> >> package java.lang; >> >> /** >> Indicates that an interface type declaration is intended to be a >> functional interface as defined by the Java Language >> Specification. Conceptually, a functional interface has exactly one >> abstract method. Since default methods are not abstract, any default >> methods declared in an interface do not contribute to its abstract >> method count. If an interface declares a method overriding one of the >> public methods of java.lang.Object, that also does not count >> toward the abstract method count. >> >> Note that instances of functional interfaces can be created with lambda >> expressions, method references, or constructor references. >> >> If a type is annotated with this annotation type, compilers are required >> to generate an error message unless: >> >>
    >>
  • The type is an interface type and not an annotation type, enum, or >> class. >>
  • The annotated type satisfies the requirements of a functional >> interface. >>
>> >> @jls 9.8 Functional Interfaces >> @jls 9.4.3 Interface Method Body >> @jls 9.6.3.8 FunctionalInterface [Interfaces in the java.lang package >> get a corresponding JLS section] >> @since 1.8 >> */ >> @Documented >> @Retention(RUNTIME) >> @Target(TYPE) >> @interface FunctionalInterface {} // Marker annotation >> >> Annotations on interfaces are *not* inherited, which is the proper >> semantics in this case. A subinterface of a functional interface can >> add methods and thus not itself be functional. There are some >> subtleties to the definition of a functional interface, but I thought >> that including those by reference to the JLS was sufficient and putting >> in all the details would be more likely to confuse than clarify. >> >> Please send comments by January 4, 2013; thanks, >> >> -Joe >> > From scolebourne at joda.org Wed Jan 2 16:23:09 2013 From: scolebourne at joda.org (Stephen Colebourne) Date: Thu, 3 Jan 2013 00:23:09 +0000 Subject: Function type naming conventions In-Reply-To: <50E48919.2060408@oracle.com> References: <50E48919.2060408@oracle.com> Message-ID: My natural reaction for IntFunction is to expect (int) -> T As such, I thought about my mental model, what the "base word" in each means - Block/Function/Predicate/Supplier - and how the primitive interacts with it. My conclusion was that the prefix should refer to the most important element of the base, the one you think about most when using it (for functions thats the input, not the output). So, I'd like to propose the following naming (only slight changes from today): If the base interface naturally has a single generic, then the primitive is prefixed: Block T -> void IntBlock int -> void Supplier () -> T IntSupplier () -> int Predicate (T) -> boolean IntPredicate (int) -> boolean UnaryOperator (T) -> T IntUnaryOperator (int) -> int BinaryOperator (T,T) -> T IntBinaryOperator (int,int) -> int BiPredicate (T,U) -> boolean IntBiPredicate (int,U) -> boolean IntDoubleBiPredicate (int,double) -> boolean This really only leaves Function. I came to the conclusion that my preference was to find an alternative base name for functions that return Int/Long/Double (in the same way that Predicate is a function that returns boolean). I came up with these naming strategies: CalcInt, CalcLong, CalcDouble FuncInt, FuncLong, FuncDouble (I wanted a properly unique name for each, like predicate, but couldn't find one, Calc is short for Calculator, and I think its my preference as it emphasises the difference from Function, like Predicate does) Thus, we now have a unique base name for each return type, so the remaining generics to be populated are all prefixes: IntFunction int -> T CalcInt T -> int BiFunction (T,U) -> R IntBiFunction (int,U) -> R IntDoubleBiFunction (int,double) -> R BiCalcInt (T,U) -> int IntDoubleBiCalcInt (int,double) -> int I believe the overall naming rule is now, "populate the generics with the prefixed primitives in order". FWIW, I dislike Indexed as it is use case sensitive. I also think BiOperator would be a much more obvious name than BinaryOperator. Stephen On 2 January 2013 19:23, Brian Goetz wrote: > Just to recap where we are in function type naming, we've got a few base > types: > > Block T -> void > Function T -> R > Predicate T -> boolean > Supplier () -> T > > Plus some derived convenience types: > > UnaryOperator extends Function > BinaryOperator extends BiFunction > > We have arity prefixes to modify the natural arity of these: > > BiFunction (T,U) -> R > BiPredicate (T,U) -> boolean > > Presumably we'll be forced into TriXxx and worse at some point, but so far > we've been able to avoid that. > > We have a primitive specialization convention that lets you prefix > {Int,Long,Double,Boolean} on front of one of these (possibly multiple > times), and this gobbles the type argument that appears in the return > position, or, if the return is not generic, the first type argument: > > IntFunction T -> int > IntSupplier () -> int > IntBiFunction (T,U) -> int > IntBinaryOperator (int,int) -> int > IntBlock int -> void > > So far we've got about 30 defined SAMs, and this has been mostly enough to > implement our libraries, including primitive specializations. > > This convention is an uneasy compromise that is part and parcel of the > compromise/commitment we made to nominal function types. Its a bit annoying > in places, but the rules above are consistent, and the names read mostly > reasonably in APIs, and better than most of the alternatives proposed, > especially the fully general Function$FromIntAndDouble$ToDouble. > > In fact, the only type we've come across repeatedly that wants a "nice" name > that doesn't fit into the above scheme is: > > int -> T > > which shows up in quite a few places. There are probably a few others but > this is the biggest. (We also came across a desire for (T,int)->T in the > reducer work, but that shows up in only one place.) > > We could treat int -> R as a specialization of Function, and extend the > naming convention to handle it, or we could try to come up with a new > top-level name for it. > > In the latter category, IndexedSupplier would work for some of the use > cases (Arrays.fill, array suppliers) but not terribly well for > IntStream.map(int -> T). > > Other ideas? From alex.buckley at oracle.com Thu Jan 3 15:49:06 2013 From: alex.buckley at oracle.com (Alex Buckley) Date: Thu, 03 Jan 2013 15:49:06 -0800 Subject: Grammar of ConstructorReference Message-ID: <50E618F2.4090704@oracle.com> The grammar of ConstructorReference is: ConstructorReference: ClassType '::' NonWildTypeArgumentsopt 'new' ArrayType '::' 'new' The class or array type which appears before the '::' is a first-class type use on which JSR 308 would like to allow annotations. JSR 308 usually catches type uses by redefining ReferenceType in JLS ch.18 from: ReferenceType: Identifier [TypeArguments] { . Identifier [TypeArguments] } to: ReferenceType: [Annotations] UnannReferenceType UnannReferenceType: Identifier [TypeArguments] {. [Annotations] Identifier [TypeArguments]} My question to the 335 EG then is, what is the ch.18 version of ConstructorReference? If it uses ReferenceType, 308 is good to go. Alex From daniel.smith at oracle.com Fri Jan 4 13:46:47 2013 From: daniel.smith at oracle.com (Dan Smith) Date: Fri, 4 Jan 2013 14:46:47 -0700 Subject: Grammar of ConstructorReference In-Reply-To: <50E618F2.4090704@oracle.com> References: <50E618F2.4090704@oracle.com> Message-ID: I have conveniently avoided Chapter 18 (because it requires a global expertise in the Ch. 18 grammar and its invariants, which I do not have). We can keep this in mind when we get around to it... ?Dan On Jan 3, 2013, at 4:49 PM, Alex Buckley wrote: > The grammar of ConstructorReference is: > > ConstructorReference: > ClassType '::' NonWildTypeArgumentsopt 'new' > ArrayType '::' 'new' > > The class or array type which appears before the '::' is a first-class type use on which JSR 308 would like to allow annotations. JSR 308 usually catches type uses by redefining ReferenceType in JLS ch.18 from: > > ReferenceType: > Identifier [TypeArguments] { . Identifier [TypeArguments] } > > to: > > ReferenceType: > [Annotations] UnannReferenceType > > UnannReferenceType: > Identifier [TypeArguments] {. [Annotations] Identifier [TypeArguments]} > > My question to the 335 EG then is, what is the ch.18 version of ConstructorReference? If it uses ReferenceType, 308 is good to go. > > Alex From alex.buckley at oracle.com Fri Jan 4 13:54:19 2013 From: alex.buckley at oracle.com (Alex Buckley) Date: Fri, 04 Jan 2013 13:54:19 -0800 Subject: Grammar of ConstructorReference In-Reply-To: References: <50E618F2.4090704@oracle.com> Message-ID: <50E74F8B.5030501@oracle.com> Dan, thanks for responding. Yes, one of the many tasks in integrating JSRs into JLS8 will be to thread 335's productions into ch.18 and 308's productions into chs.2-15. Alex On 1/4/2013 1:46 PM, Dan Smith wrote: > I have conveniently avoided Chapter 18 (because it requires a global expertise in the Ch. 18 grammar and its invariants, which I do not have). We can keep this in mind when we get around to it... > > ?Dan > > On Jan 3, 2013, at 4:49 PM, Alex Buckley wrote: > >> The grammar of ConstructorReference is: >> >> ConstructorReference: >> ClassType '::' NonWildTypeArgumentsopt 'new' >> ArrayType '::' 'new' >> >> The class or array type which appears before the '::' is a first-class type use on which JSR 308 would like to allow annotations. JSR 308 usually catches type uses by redefining ReferenceType in JLS ch.18 from: >> >> ReferenceType: >> Identifier [TypeArguments] { . Identifier [TypeArguments] } >> >> to: >> >> ReferenceType: >> [Annotations] UnannReferenceType >> >> UnannReferenceType: >> Identifier [TypeArguments] {. [Annotations] Identifier [TypeArguments]} >> >> My question to the 335 EG then is, what is the ch.18 version of ConstructorReference? If it uses ReferenceType, 308 is good to go. >> >> Alex > From mernst at cs.washington.edu Thu Jan 10 14:46:47 2013 From: mernst at cs.washington.edu (Michael Ernst) Date: Thu, 10 Jan 2013 14:46:47 -0800 (PST) Subject: Lambda spec suggestion (section 15.27) Message-ID: <20130110.144647.352885397217022164.mernst@cs.washington.edu> Section 15.27 says: Examples of method and constructor references: System::getProperty "abc"::length String::length super::toString ArrayList::new It would be useful to show examples that use type arguments as well, such as ArrayList::new which is better style anyway (no raw types!). -Mike