Reified Lambda Functions

Howard Lovatt howard.lovatt at iee.org
Fri Jan 8 04:19:41 PST 2010


Hi Neal,

Comments inline below.

2010/1/7 Neal Gafter <neal at gafter.com>

> On Thu, Jan 7, 2010 at 3:08 AM, Howard Lovatt <howard.lovatt at iee.org>
> wrote:
> > I have posted a *more* formal proposal for reifying lambdas (as suggested
> by
> > Neal Gafter):
> > http://www.artima.com/weblogs/viewpost.jsp?thread=278567
> > This could be read in conjunction with the original informal proposal:
> > http://www.artima.com/weblogs/viewpost.jsp?thread=277879
> > Which is an easier read :)
>
> Having looked at these, most of what was unclear to me before is still
> unclear.  I still don't know *when* this specification requires the
> conversions via the "From" classes, and when it doesn't.  The
> description is too informal to intuitively map to a specification.
>

I have updated section 5. to include a summary of when conversions are
applied. I will also go through your example below and see if things are
clearer.

>
> Back to my last example, I still do not see how this specification handles
> it:
>
> Consider a method that returns a generic list of functions:
>
> <T> List<#T()> lazify(List<T> data) {
>    List<#T()> result = new ArrayList<#T()>();
>    for (T t : data) result.add(#()t); // adds element of type Callable$0<T>
>    return result;
> }
>

This is translated to:

  static <T> List<$Callable$0<? extends T>> lazify(List<T> data) {
    List<$Callable$0<? extends T>> result = new ArrayList<$Callable$0<?
extends T>>();
    for (final T t : data) result.add(new $Callable$0<T>() {
      @Override public T call() { return t; }
    }); // adds element of type Callable$0<T>
    return result;
  }

(I added static to make my testing easier.) I think this is exactly what you
were expecting - yes?


> the list that is returned contains lambdas of type Callable$0<T>.
> Then we call it on some data
>
> List<#String()> alphabet() {
>    return lazify(Arrays.asList("a", "b", "c"));
> }
>

This gets translated to:

  static List<$Callable$0<? extends String>> alphabet() {
    return lazify(Arrays.asList("a", "b", "c"));
  }

Again I think this is what you expected - yes?


> List<#String()> alphabet = alphabet();
>
> now alphabet contains a List whose elements are of type
> Callable$0<String> (but the compiler probably thinks those elements
> are of type Callable$String).  So we pull a datum out of it.
>
> #String() firstLetter = alphabet.get(0);
>

These two lines get translated to:

  static void nealLazifyExample() {
    List<$Callable$0<? extends String>> alphabet = alphabet();
    $Callable$String firstLetter =
$From$0$String$$To$String.instance(alphabet.get(0));
    System.out.println("firstLetter = " + firstLetter.call());
  }

(I added the 'neal' method and 'print' line to make my testing easier - it
prints "firstLetter = a".) The relevant conversion method generated by the
loader is:

  public final class $From$0$String$$To$String extends $Callable$String
implements $Wrapper {
    private final $Callable$0<? extends String> f;
    private $From$0$String$$To$String(final $Callable$0<? extends String> f)
{ this.f = f; }
    public static $Callable$String instance(final $Callable$0<? extends
String> from) {
      final $Callable$0<? extends String> f = ($Callable$0<? extends
String>)Wrappers.unWrap(from);
      if (f instanceof $Callable$String) { return ($Callable$String)f; }
      return new $From$0$String$$To$String(f);
    }
    @Override public String call() { return f.call(); }
    @Override public Object getWrapee() { return f; }
    @Override public int hashCode() { return f.hashCode(); }
  }


> Now we've assigned something of type Callable$0<String> to something
> of type Callable$String.  Where in the execution of this code did the
> "cast" occur?
>

The conversion ('cast') occurs when you assign a lambda to a lambda
variable, in this case the line "#String() firstLetter = alphabet.get(0);".
The rules for this conversion are in section 5, it now says (this is my
update):

   1. If the type of _lValue_ is generic, do nothing.
   2. If the type of _rExpression_ is exactly the same as the type
   of _lValue_, do nothing.
   3. If the type of _rExpression_ is generic, possibly insert a reifying
   conversion (see section 5.3.1).
   4. If the type of _rExpression_ is reified, possibly insert a
   contravariant-overriding conversion (see section 5.3.2).

The type of _lValue_ is $Callable$String and it is therefore reified, hence
point 1 above isn't applicable. The type of the _rExpression_ is
$Callable$0<? extends String> and is therefore generic, hence points 2 and
4 aren't applicable. Which leaves 3 and section 5.3.1 describes the
transformation to apply.

I hope this explains things a little better and thanks for the feedback,

 -- Howard.

>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit http://www.messagelabs.com/email
> ______________________________________________________________________
>



-- 
 -- Howard.


More information about the lambda-dev mailing list