Casts as closure contexts?

367 views
Skip to first unread message

Bill Burdick

unread,
Jan 30, 2012, 3:33:18 PM1/30/12
to xtend...@googlegroups.com
It seems like

val type v = closure


Should be the same as

val v = closure as type


but the cast doesn't seem to provide a context for the closure.  Shouldn't a cast provide a context for closure coercion?


Bill

Sven Efftinge

unread,
Jan 30, 2012, 3:48:52 PM1/30/12
to xtend...@googlegroups.com
Yes, it should. I know there are test cases verifying that.
Please file a bugzilla with reproducible example.

Thanks,
Sven

Bill Burdick

unread,
Jan 30, 2012, 4:04:09 PM1/30/12
to xtend...@googlegroups.com
OK, I'll look at it.  Of course, I'm using a Frankenstein version 2.3 of Xtend, with my (closure -> abstract class) change (plus a lot of other 2.3 code for dependencies) grafted onto a 2.2 install.  To test it, I'll have to try it with a vanilla 2.2 install.


Bill

Sebastian Zarnekow

unread,
Jan 30, 2012, 4:04:39 PM1/30/12
to xtend...@googlegroups.com
Hi,

it's currently not possible to use the type information of a cast expression. Please consider the following scenario:

def <T extends Integer> cannotUseCastContext() {
[T a,T b|a+b] as (T,T)=>T
}

a + b will return an Integer / int but the cast would imply that 'T' has to be returned. Unfortunately, Integer is not a T.
The equivalent Java code won't compile either:


public <T extends Integer> Function<? super T, ? extends T> similarThingInJava() {
return new Function<T, T>() {
public T apply(T input) {
return Integer.valueOf(input + input);
}
};
}

Type mismatch: cannot convert from Integer to T

You'd have to cast the result explicitly to T or use an unsafe cast like

return (Function<? super T, ? extends T>) new Function<T, Integer>() {
public Integer apply(T input) {
return Integer.valueOf(input + input);
}
};

which is basically what the previous Xtend example does.
Nevertheless, please feel free to file a ticket.

Regards,
Sebastian

signature.asc

Sven Efftinge

unread,
Jan 30, 2012, 4:45:45 PM1/30/12
to xtend...@googlegroups.com
But how is that different to using the type in a variable declaration?
I see the same problem with the following code:

public <T extends Integer> void foo() {
Function<? super T, ? extends T> func = new Function<T,T>() {
public T apply(T input) {
return Integer.valueOf(input + input);
}
};
}

Isn't the problem here that "T extends Integer" doesn't define a lower bound and therefore nothing but T is compatible?
I see the issue, but don't get how it is related to Bill's initial question. I checked btw. and function conversion using casts at least works for Supplier and Provider from guice and guava.

Bill Burdick

unread,
Jan 30, 2012, 4:47:50 PM1/30/12
to xtend...@googlegroups.com
It looks like this fails, as well (at least it does in my modified version of the plugin):

def <T extends Integer> duh() {
val (T, T)=>T block = [a,b|a+b]
block
}

So I don't think it really has to do with my point.  What I'm saying is that if this works,

val type v = closure

then this also ought to work,

val v = closure as type

I.e. it seems to me that closures should be able to use type information equally from declarations or from casts in order to do coercion.


Bill

Sebastian Zarnekow

unread,
Jan 30, 2012, 4:51:26 PM1/30/12
to xtend...@googlegroups.com
The problem with the cast information is, that 

[T a,T b|a+b] as (T,T)=>T

Will infer (T, T)=>Integer which is casted (unsafe) to (T,T)=>T. That would not be possible if we'd try to use the cast information for type inference in the first place.

Equivalent Java would be:

public <T extends Integervoid foo() {
return (Function<? super T, ? extends T>new Function<T,Integer>() {
public Integer apply(T input) {
return Integer.valueOf(input + input);
}
};
}

Regards,
Sebastian
signature.asc

Sebastian Zarnekow

unread,
Jan 30, 2012, 4:59:35 PM1/30/12
to xtend...@googlegroups.com
Hi Bill,

it's unfortunately another quality of information. A cast may be unsafe and enforce a certain type which is not necessarily the statically known type as declarable on the lhs of a variable declaration. Therefore it's expected that your testcase fails with type (T, T)=>T declared statically. The point is, that it would succeed at runtime by tricking the compiler / using type erasure. That would not be possible if cast-types would be first class citiizens in the type inference engine as explicitly declared types are. However, I like the idea but wanted to point out, that a cast expression and a declared type are unlikely to have the same quality.

Regards,
Sebastian
signature.asc

Bill Burdick

unread,
Jan 30, 2012, 5:03:27 PM1/30/12
to xtend...@googlegroups.com
Supplier and Provider, in which the method takes no arguments, work for me, but Function, in which the function takes one argument, does not.  The class which originally failed for me also had an abstract method of one argument.  Maybe you could verify?

This works,

var Function<Integer, Integer> s = [x|x * 2]

This does not work,

var s = [x|x * 2] as Function<Integer,Integer>

I get these errors:

Multiple markers at this line
- There is no context to infer the closure's argument types from.
   Consider typing the arguments or put the closures into a typed
   context.
- Couldn't resolve reference to JvmIdentifiableElement '*'.


Bill

Bill Burdick

unread,
Jan 30, 2012, 5:05:33 PM1/30/12
to xtend...@googlegroups.com
By the way, the class I was testing with was an abstract class, so it won't work in your version, but it did not use generics.  Here it is:

public abstract class SimpleSelectionAdapter extends SelectionAdapter {
public abstract void widgetSelected(SelectionEvent e);
}


Bill

Sven Efftinge

unread,
Jan 30, 2012, 5:14:15 PM1/30/12
to xtend...@googlegroups.com
Please submit a bug report.

Thanks,
Sven

Sven Efftinge

unread,
Jan 30, 2012, 5:17:24 PM1/30/12
to xtend...@googlegroups.com
If you want a quick fix for your fork change the following in XbaseTypeProvider:

protected JvmTypeReference _expectedType(XCastedExpression expr, EReference reference, int index, boolean rawType) {
return expr.getType();
} 

We'll have to see if and how we can support this.

On Jan 30, 2012, at 11:05 PM, Bill Burdick wrote:

Bill Burdick

unread,
Jan 30, 2012, 5:27:46 PM1/30/12
to xtend...@googlegroups.com
I agree that a cast and a declaration may not necessarily have the same quality and although not all casts may work, I think the Xtend complier should be able to coerce a closure properly if it is cast to a type that would successfully coerce a closure in a declaration using that same type, e.g. both

val Provider p = [|3]

and

val p = [|3] as Provider

should work.

This would allow you, for example, to disambiguate a call to an overloaded method which takes either a Supplier or a Provider by using the closure with a cast directly as an argument instead of having to declare a variable just for coercion's sake.

Right now, the error Xtend gives me for ([x|x * 2] as Function<Integer,Integer>) says that there is no context available from which to infer the closure's argument type and suggests putting the closure into a typed context (i.e. it doesn't even make an attempt to coerce it).  I think that in fact it is already in a typed context with all of the information Xtend needs to infer the argument type properly.


Bill

Bill Burdick

unread,
Jan 30, 2012, 5:28:49 PM1/30/12
to xtend...@googlegroups.com
Sven, if this code also does not work for you, I will be happy to create a ticket for it.


Bill


On Mon, Jan 30, 2012 at 4:03 PM, Bill Burdick <bill.b...@gmail.com> wrote:

Bill Burdick

unread,
Jan 30, 2012, 5:33:05 PM1/30/12
to xtend...@googlegroups.com
The link from the Xtend site's Community menu goes uses the TMF product: https://bugs.eclipse.org/bugs/enter_bug.cgi?product=TMF&component=Xtext&version=2.1.0&short_desc=%5BXtend%5D

I'm guessing I should use the Xtend product in the bug report, right?


Bill

Sven Efftinge

unread,
Jan 31, 2012, 1:12:30 AM1/31/12
to xtend...@googlegroups.com
Yes, we just moved Xtend to its own project at Eclipse.
We will update the links accordingly in the next day.

Sven Efftinge

unread,
Jan 31, 2012, 1:17:31 AM1/31/12
to xtend...@googlegroups.com
def <T extends Integer> foo() {
  [a,b | a + b ] as (T, T) => T
}

should result in the same error message as in Java : "Type mismatch: cannot convert from Integer to T"

And if I write

def <T extends Integer> foo() {
  [a,b | (a + b) as T ] as (T, T) => T
}

the compiler should be fine.

Daniel Dietrich

unread,
Feb 1, 2012, 2:45:30 AM2/1/12
to xtend...@googlegroups.com
I think this does go in the same direction:

This works:

  Set<String> strings

  static (int,int)=>int min = [i,j | if (i < j) i else j]

  

  def go() {

    strings.map[index].reduce(min)

  }

  

  def index(String s) {

    s.hashCode

  }


But this does not work:

  Set<String> strings

  static (int,int)=>int min = [i,j | if (i < j) i else j]

  static (String)=>int index = [s | s.hashCode]

  

  def go() {

    // Incompatible receiver type.

    // Expected java.lang.Iterable<java.lang.Integer>

    // or java.lang.Integer[] or int[]

    // but was java.lang.Iterable<? extends java.lang.Integer>

    strings.map(index).reduce(min)

  }


Daniel

Sebastian Zarnekow

unread,
Feb 1, 2012, 3:34:19 AM2/1/12
to xtend...@googlegroups.com
Hi Daniel,


Thanks for the example,
Sebastian
signature.asc

Daniel Dietrich

unread,
Feb 1, 2012, 3:52:22 AM2/1/12
to xtend...@googlegroups.com
Thank you, Sebastian.
 
You all do a great job with Xtend!

Bill Burdick

unread,
Feb 1, 2012, 10:22:48 AM2/1/12
to xtend...@googlegroups.com
I agree -- you guys made a lot of really good decisions, like generating Java source, etc.  I really like where it's going!


Bill

McKinley

unread,
Feb 1, 2012, 4:08:23 PM2/1/12
to Xtend Programming Language
Yes, generating Java code has the interesting effect of allowing mere
mortals to file bug reports with simple reproducible examples. If it
were direct to byte code, that would be far more complicated.

Great work!

On Feb 1, 7:22 am, Bill Burdick <bill.burd...@gmail.com> wrote:
> I agree -- you guys made a lot of really good decisions, like generating
> Java source, etc.  I really like where it's going!
>
> Bill
>
> On Wed, Feb 1, 2012 at 2:52 AM, Daniel Dietrich <cafeb...@googlemail.com>wrote:
>

Sven Efftinge

unread,
Feb 2, 2012, 3:04:44 AM2/2/12
to xtend...@googlegroups.com
Thank you Bill and Daniel for the nice words.

Sven Efftinge

unread,
Feb 2, 2012, 3:07:10 AM2/2/12
to xtend...@googlegroups.com
And you, of course :-)
It's also for us simpler to understand what's wrong with the compiler.
The downside is when compiling to a very rigid statically typed language you need to do a lot of thinks just to make the second static checker happy.
But it's doable and definitely worth it.
Reply all
Reply to author
Forward
0 new messages