This page is no longer maintained — Please continue to the home page at www.scala-lang.org

"Nothing" can not cast and assigned to a val, but no compiler warning/error message?

1 reply
Caoyuan
Joined: 2009-01-18,
User offline. Last seen 42 years 45 weeks ago.

This is another corner case when I write real world Scala application.

There is a Java class takes type parameter T, T is anything:
================
package dcaoyuan.test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author dcaoyuan
*/
public class AList implements Iterator {

List a = new ArrayList();

{
a.add((T) "string");
}

Iterator itr = a.iterator();

public boolean hasNext() {
return itr.hasNext();
}

public T next() {
return itr.next();
}

public void remove() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
=========

Which implemented java.util.Iterator with type parametered hasNext()
and next() methods. Notice here next() will return T

Now let's try to call it in Scala:
================
/*
* Main.scala
*
*/
package dcaoyuan.test

object Main {

def main(args: Array[String]) :Unit = {
testAList_work
testAList_unwork
}

def testAList_work :Unit = {
val a :AList[_] = new AList
// a is inferred as AList[Any]
while (a.hasNext) {
val e = a.next
println(e)
}
}

def testAList_unwork :Unit = {
val a = new AList
// a is inferred as AList[Nothing]
while (a.hasNext) {
// now a.next is Nothing, can not cast to "val e", which
should at least be Any
val e = a.next // will throw java.lang.ClassCastException
println(e)
}
}
}
================

I wrote two functions: "testAList_work" and "testAList_unwork"

The issue is in testAList_unwork, as a simple "val a = new AList", "a"
will be inferred as AList[Nothing] by scalac, so, "a.next" will return
an instance of type "Nothing", then, "val e = a.next" will throw
java.lang.ClassCastException

My question is, should this corner case be checked by scalac as an
error or warning?

-Caoyuan

Carsten Saager
Joined: 2008-12-19,
User offline. Last seen 42 years 45 weeks ago.
Re: "Nothing" can not cast and assigned to a val, but no compi
The Java compiler should give you a warning for an unchecked cast at

 a.add((T) "string");

Nothing is the type that can be assign to any other type (Nil is List[Nothing]) - it doesn't work vice-versa that is why you get the CCE.
I don't think Scala can warn you about that as the problem is the ignored warning in the implementation of AList

-Carsten

On Sun, Feb 15, 2009 at 7:59 AM, Caoyuan <dcaoyuan [at] gmail [dot] com> wrote:
This is another corner case when I write real world Scala application.

There is a Java class takes type parameter T, T is anything:
================
package dcaoyuan.test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author dcaoyuan
 */
public class AList<T> implements Iterator<T> {

   List<T> a = new ArrayList<T>();

   {
       a.add((T) "string");
   }

   Iterator<T> itr = a.iterator();

   public boolean hasNext() {
       return itr.hasNext();
   }

   public T next() {
       return itr.next();
   }

   public void remove() {
       throw new UnsupportedOperationException("Not supported yet.");
   }
}
=========

Which implemented java.util.Iterator with type parametered hasNext()
and next() methods. Notice here next() will return T

Now let's try to call it in Scala:
================
/*
 * Main.scala
 *
 */
package dcaoyuan.test

object Main {

   def main(args: Array[String]) :Unit = {
       testAList_work
       testAList_unwork
   }

   def testAList_work :Unit = {
       val a :AList[_] = new AList
       // a is inferred as AList[Any]
       while (a.hasNext) {
           val e = a.next
           println(e)
       }
   }

   def testAList_unwork :Unit = {
       val a = new AList
       // a is inferred as AList[Nothing]
       while (a.hasNext) {
           // now a.next is Nothing, can not cast to "val e", which
should at least be Any
           val e = a.next // will throw java.lang.ClassCastException
           println(e)
       }
   }
}
================

I wrote two functions: "testAList_work" and "testAList_unwork"

The issue is in testAList_unwork, as a simple "val a = new AList", "a"
will be inferred as AList[Nothing] by scalac, so, "a.next" will return
an instance of type "Nothing", then, "val e = a.next" will throw
java.lang.ClassCastException

My question is, should this corner case be checked by scalac as an
error or warning?

-Caoyuan

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland