On Oct 12, 2018, at 10:15 AM, Brian Goetz <brian.go...@oracle.com> wrote: > > Summary: > > - Both the capture-this and drop-this cases have important motivating use > cases > - Arbitrarily dropping one or the other would compromise the feature > - There are some possibly reasonable ways of doing overload resolution and > adaptation here, at some complexity. >
+100 One reason this proposal is so very powerful is that it allows the original 'this' passed to the CMB-defined method to serve either, or both, or neither of two independent roles: Use-1. Find a data-dependent object (a field 'f' of 'this', or 'this' itself) to delegate the operation; this delegate will execute the target method as the next 'this'. The method reference is of the form 'this::target' or 'field::target' (where 'field' is treated as 'this.field'). Use-2. Pass 'this' as a passive (non-receiver) argument to the target method, which may choose to use the original 'this' value in some way. The method reference is of the form 'sf::target' or 'T::target', where 'sf' may be a static field or perhaps another constant. (Non-use-1. If 'this' does not locate a data-dependent object, such an object may still be obtained from another source 'x', such as a static variable in the class or another parameter of the method. The method reference is of the form 'x::target'. The method reference may also refer to a static method, as 'T::sm', in which case there is no receiver needed, and no data dependency at all.) (Non-use-2. If 'this' is not passed as a passive argument, then only the explicit arguments of the original method are passed.) Use-1 vs. non-use-1 is determined by the expression before the '::' in the method reference. Does this expression make use (explicit or implicit) of 'this', or does it only use statically available names and parameter names? Use-2 vs. non-use-2 is determined by the arity of the matching method: Does it accept the use-2 passive argument value 'this', in which case this value is injected as a new passive argument, or is it dropped? There are thus four shapes of target method invocations, with respect to their use or non-use of 'this': Static call (neither 1 or 2): The target method uses only the explicit parameters. It may be as simple as a constant-returning method, or a method that derives a value from one of the arguments. Delegate or bridge call (1, not 2): The target method is called on a "friend" of the the original object. The original object may call a different method on itself; this is a bridging pattern. Concept invocation (2, not 1): The class of 'this' (but not 'this' itself) declares a handler method to execute on behalf of the original 'this', which is passed as an argument. Prototype invocation (both 1 and 2): The original receiver object passes the request to a friend object, *and* passes along its own identity. It is as if each object has the option of carrying around its own customized Concept, rather than all objects of a given class using a common Concept. (The term "Concept" comes from C++. I'm not fond of it, but I don't have a better term than "function". In Lisp or Haskell everything is a "Concept". What a concept.) Examples: int computeLength(String s) = String::length; // Static for some LengthComputer int getAsInt() = MY_RAND::nextInt; // Static for some IntSupplier int size() = inner::size; // Delegate for some wrapping List T get(int x) = inner::get; // Delegate for same long longHash() = this::hashCode; // Bridge for some LongHashable long longHash() = ThisClass::hashCode; // Same effect via different path long longHash() = ::hashCode; // Same effect via different path void reverse() = Collections::reverse; // Concept for some List int compareTo(List that) = MY_LEX_COMPER::compare(); // Concept for some List String toString() = MY_TO_STRINGER::stringOf; // Concept for some Object void mouseClicked(MouseEvent e) = myEventParent::mouseClickedFor; // Prototype (Similar comments might be made about patterns which delegate to explicit method parameters, which in some sense are "just as deserving of attention" as the implicit 'this' parameter. Delegating to an explicit parameter amounts to an immediate callback. However, the CMB proposal doesn't need to support such things via method references, and the question of dropping a non-'this' parameter would seem to be a vexed one.) The Prototype pattern may seem far-fetched, but there are times when it's useful. It has been used to to join and generalize both regular class-based inheritance and delegation; in this use the delegate is called the "parent" in Self and "protoype" in JavaScript. But I don't need to plump for Prototypes in order to observe that the two "axes" of method reuse, Delegation and Concepts, are both really, really useful by themselves. If I had to choose one this-using pattern, it would be Concepts, but I think it would be hard to drop Delegation given the natural way it also fits into the CMB proposal. Since CMBs give us all four patterns under one powerful rubric, I say let's take all four and say thank you. — John