PS: Another way to look at the potential differences between both definitions, is using :javap.
scala> class Compare {
| def compileAndRunX(vm: VirtualMachine[A] forSome {type A}): Unit = vm match { case vm: VirtualMachine[e] => vm.run(vm.compile) }
| def compileAndRunPoly[A](vm: VirtualMachine[A]): Unit = vm.run(vm.compile)
| }
defined class Compare
scala> :javap -vc Compare
<...>
public void compileAndRunX(VirtualMachine<?>);
descriptor: (LVirtualMachine;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: aload_1
1: ifnull 26
4: aload_1
5: invokeinterface #13, 1 // InterfaceMethod VirtualMachine.run:()Lscala/Function1;
10: aload_1
11: invokeinterface #17, 1 // InterfaceMethod VirtualMachine.compile:()Ljava/lang/Object;
16: invokeinterface #23, 2 // InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
21: checkcast #25 // class scala/runtime/BoxedUnit
24: pop
25: return
26: new #27 // class scala/MatchError
29: dup
30: aload_1
31: invokespecial #31 // Method scala/MatchError."<init>":(Ljava/lang/Object;)V
34: athrow
<...>
public <A extends java.lang.Object> void compileAndRunPoly(VirtualMachine<A>);
descriptor: (LVirtualMachine;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: invokeinterface #13, 1 // InterfaceMethod VirtualMachine.run:()Lscala/Function1;
6: aload_1
7: invokeinterface #17, 1 // InterfaceMethod VirtualMachine.compile:()Ljava/lang/Object;
12: invokeinterface #23, 2 // InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
17: pop
18: return
LocalVariableTable:
Start Length Slot Name Signature
0 19 0 this LCompare;
0 19 1 vm LVirtualMachine;
LineNumberTable:
line 13: 0
Signature: #61 // <A:Ljava/lang/Object;>(LVirtualMachine<TA;>;)V