New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
propagate bounds from class type params to existential quantifiers #6169
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6169?orig=1
|
DaveScala (davescala) said: |
@retronym said (edited on Mar 30, 2013 9:29:03 PM UTC): object Main {
def foo(b: CircleBuilderScala[_]) =
b.foo.foo // error: value foo is not a member of _$1
}
class CircleBuilderScala[B <: CircleBuilderScala[B]] {
def foo: B = ???
}
See also #4745 and other tickets about f-bounded type parameters + type inference. |
@retronym said: scala> type CircleBuilderF = ({type CB <: CircleBuilder[CB]; type CB1 = CB with CircleBuilder[CB]})#CB1
defined type alias CircleBuilderF
scala> def newCircleBuilder: CircleBuilderF = CircleBuilder.create.asInstanceOf[CircleBuilderF]
newCircleBuilder: CircleBuilderF
scala> newCircleBuilder.centerX(0).centerX(0).build()
res28: javafx.scene.shape.Circle = Circle@38b9a306 Now, if we can just figure out how to roll this into the compiler... |
@retronym said (edited on Mar 31, 2013 10:40:42 AM UTC): scala> implicit class RichFBoundBuilder[B[X <: B[X]]](val _builder: B[_]) {
type B1 = X forSome { type X <: B[X] }
def asScala: B1 = _builder.asInstanceOf[B1]
}
warning: there were 2 feature warning(s); re-run with -feature for details
defined class RichFBoundBuilder
scala> import javafx.scene.shape._
import javafx.scene.shape._
scala> CircleBuilder.create.asScala.centerX(0).centerX(0).build()
res0: javafx.scene.shape.Circle = Circle@6c60efe7 |
Stephen Compall (s11001001) said: Welcome to Scala version 2.10.1 (OpenJDK Client VM, Java 1.6.0_27).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
implicit class RichFBoundBuilder[B[X <: B[X]]](val _builder: B[_]) {
type B1 = X forSome { type X <: B[X] }
def asScala: B1 = _builder.asInstanceOf[B1]
}
// Exiting paste mode, now interpreting.
defined class RichFBoundBuilder
scala> (x: List[Int]) => x.asScala
res0: List[Int] => X forSome { type X <: List[X] } = <function1> |
@retronym said: |
Stephen Compall (s11001001) said (edited on Apr 2, 2013 7:03:48 PM UTC): I don't see how 6169 can be fixed, interop-wise, if #7318 isn't a bug, though. |
@retronym said: scala> import javafx.scene._, shape._import javafx.scene._
import shape._
scala> implicit class RichJavaFXBuilder[B[X <: B[X]] <: NodeBuilder[_]](val _builder: B[_]) {
| type B1 = X forSome { type X <: B[X] }
| def asScala: B1 = _builder.asInstanceOf[B1]
| }
warning: there were 2 feature warning(s); re-run with -feature for details
defined class RichJavaFXBuilder
scala> CircleBuilder.create().asScala.centerX(0).centerX(0).build()
res3: javafx.scene.shape.Circle = Circle@2becc08c
scala> List(1).asScala
<console>:20: error: value asScala is not a member of List[Int]
List(1).asScala
^ |
Stephen Compall (s11001001) said: (in 2.11.0-M3, a variant of 1786's sample code): abstract class SomeClass2[T] {def tValue: T}
class MyClass2[T <: SomeClass2[T]](val myValue:T)
def myMethod(i:MyClass2[_]) {
i.myValue.tValue // << error: value tValue is not a member of _$1
}
def myMethod[T <: SomeClass2[T]](i:MyClass2[T]) {
i.myValue.tValue // << works
} |
Stephen Compall (s11001001) said: |
@adriaanm said: |
Stephen Compall (s11001001) said: public final class It<T extends String>
{
private final T _it;
public It(T it){_it = it;}
public static It<?> instance() {
return new It<String>("42");
}
public static It<? extends String> instance2() {
return instance();
}
public T it(){return _it;}
} scala> It.instance.it
res1: Any = 42
scala> It.instance2.it
res2: String = 42 |
@adriaanm said: |
@adriaanm said: |
Stephen Compall (s11001001) said: |
@adriaanm said (edited on Jan 29, 2014 6:36:39 PM UTC): public static It<?> instance();
descriptor: ()LIt;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=0, args_size=0
0: new #3 // class It
3: dup
4: ldc #4 // String 42
6: invokespecial #5 // Method "<init>":(Ljava/lang/String;)V
9: areturn
LineNumberTable:
line 7: 0
Signature: #19 // ()LIt<*>; |
@adriaanm said: public static It<? extends java.lang.String> instance2();
descriptor: ()LIt;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: invokestatic #6 // Method instance:()LIt;
3: areturn
LineNumberTable:
line 11: 0
Signature: #21 // ()LIt<+Ljava/lang/String;>;
|
@adriaanm said (edited on Feb 4, 2014 8:35:43 AM UTC): The idea is to do a bit more work during classfile parsing (while trying to avoid cycles) to propagate bounds declared on a class's type params to the corresponding existential quantifiers that abstract over them. |
Stephen Compall (s11001001) said: |
@adriaanm said: |
@adriaanm said: |
@adriaanm said: |
@retronym said: https://github.com/retronym/slick/compare/tmp;2.11-compat-2?expand=1 #1786 actually seems to be a step backwards. Before, slick left off a lot of existential bounds, but because it did that across the boards we it actually got away with it. Now, depending on compilation order, some bounds are inferred, and others aren't. The inferred bounds are infectious; type errors spring up in other places. [error] /Users/jason/code/slick/slick-testkit/src/main/scala/com/typesafe/slick/testkit/tests/JdbcMapperTest.scala:194: class PairShape needs to be abstract, since method copy in class ProductNodeShape of type (shapes: Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]])scala.slick.lifted.Shape[Level, _, _, _] is not defined
[error] (Note that Seq[scala.slick.lifted.Shape[_ <: scala.slick.lifted.ShapeLevel, _, _, _]] does not match Seq[JdbcMapperTest.this.tdb.profile.simple.Shape[_, _, _, _]]: their type parameters differ)
[error] final class PairShape[Level <: ShapeLevel, M <: Pair[_,_], U <: Pair[_,_], P <: Pair[_,_]](val shapes: Seq[Shape[_, _, _, _]]) extends MappedScalaProductShape[Level, Pair[_,_], M, U, P] {
[error] So I can see the attraction of deferring the bounds sharpening until subtype checks. |
@adriaanm said: |
see attachments
In java you can write
This is a builder pattern which make use of existential f-bounds
The problem is that in scala the skolems get erased after two method calls and so the next method doesn't exist.
if I javap the java code
then I can see that the names and types are stored in bytecode (so a sort of runtime type info / refied generics)
In scala:
causes
The only way to solve it in scala is to do a downcast after two methods (.asInstanceOf[CircleBuilder[_]]) or implicit conversion or to generate reified skolems _$x beforehand.
which generates $_1, $_2 and $_3 for calling 6 methods (2 per skolem)
This looks a bit hackish to me and very unscala.
associated thread:
https://groups.google.com/forum/?hl=en&fromgroups#!topic/scala-user/Op79HcAoj2M
The text was updated successfully, but these errors were encountered: