List(1,2,3).isInstanceOf[Serializable] == true, but assigning it to val list: Serializable fails?

154 views
Skip to first unread message

Simon Ochsenreither

unread,
Apr 20, 2013, 5:35:44 PM4/20/13
to scala-l...@googlegroups.com
Consider this:

scala> val list: Serializable = List(1,2,3)
<console>:7: error: type mismatch;
 found   : List[Int]
 required: Serializable
       val list: Serializable = List(1,2,3)
                                    ^

scala> List(1,2,3).isInstanceOf[Serializable]
res4: Boolean = true


Am I missing something crucial or does this look like a bug?

Thanks,

Simon

Tom Switzer

unread,
Apr 20, 2013, 5:42:09 PM4/20/13
to scala-l...@googlegroups.com

List doesn't extend Serializable but :: does?

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Chris Hodapp

unread,
Apr 20, 2013, 6:00:36 PM4/20/13
to scala-l...@googlegroups.com
To be more explicit (I'm sure Simon is aware of this, but just not thinking of it), you can have:
scala> class C
defined class C

scala> val c = new C
c: C = C@24db4c57

scala> (c: Any).isInstanceOf[C]
res0: Boolean = true

scala> val x: C = (c: Any)
<console>:9: error: type mismatch;
 found   : Any
 required: C
       val x: C = (c: Any)
                    ^
In other words, isInstanceOf is reflective.

Paul Phillips

unread,
Apr 20, 2013, 6:14:47 PM4/20/13
to scala-l...@googlegroups.com

On Sat, Apr 20, 2013 at 2:35 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
Am I missing something crucial or does this look like a bug?

It seems that both Nil and :: declare SerialVersionUID, and List doesn't. Are only leaf nodes supposed to be marked serializable? That's my only hypothesis.

Tom Switzer

unread,
Apr 20, 2013, 6:20:02 PM4/20/13
to scala-l...@googlegroups.com
There was a conversation about this a while back. I remember people were basically saying you shouldn't ask for a Serializable, but just ask for Any and check if it is serializable. The reason being that an interface shouldn't dictate whether something can be serializable (ie. while it makes sense for List, it doesn't make sense for Seq). And since people often don't interact with concrete subtypes, that requiring Serializable as a type to a method would be too restrictive.


--

Simon Ochsenreither

unread,
Apr 20, 2013, 7:03:47 PM4/20/13
to scala-l...@googlegroups.com
The reason being that an interface shouldn't dictate whether something can be serializable (ie. while it makes sense for List, it doesn't make sense for Seq). And since people often don't interact with concrete subtypes, that requiring Serializable as a type to a method would be too restrictive.

Yes, but what is the benefit of having a sealed non-serializable supertype of two serializable subclasses?

Also not quite intuitive:

scala> val s: Serializable = ""

<console>:7: error: type mismatch;
 found   : String("")
 required: Serializable
       val s: Serializable = ""
                             ^

scala> val s: java.io.Serializable = ""
s: java.io.Serializable = ""


It is completely logical from a typing POV (scala.Serializable is a subtype of java.io.Serializable), but imho it makes pretty much no sense from a language design POV.
Why isn't this just a simple type alias to the platform's appropriate Serializable?

Same thing with scala.Cloneable.

Aleksey Nikiforov

unread,
Apr 20, 2013, 8:07:19 PM4/20/13
to scala-l...@googlegroups.com
The problem with List[T] is that T can be anything, including strictly non-serializable types. The question then becomes: Is a List of non-serializable object itself serializable? The answer, of course, is no. So List[T] does not have to extend Serializable.

On the other hand, just because an object extends Serializable does not mean it will successfully serialize at runtime, because it can have non-serializable field values.

So, strictly speaking, being serializable is a runtime property, and cannot be enforced at the type level without excessive duplication. To do so would require two versions for each collection: SerializableList[T <: EnforcedSerializable] and List[T <: Any]. Not to mention duplications of any other class that allows non-serializable fields.

Now that we have all the details, it is easy to see that "extends Serializable" is simply an implementation detail. Scala used to have @serializable annotation instead, which made more sense...

To summarize: serialization APIs should just take Any instead of Serializable, since Serializable type is nothing more than an implementation detail leaked into the type system.


Simon Ochsenreither

unread,
Apr 20, 2013, 8:24:28 PM4/20/13
to scala-l...@googlegroups.com
Well, any combination of Serializable and a generic class should be read as "could be serializable, depending on the generic type". If you care, you could also define the generic type with Serializable as an upper bound. Then it is "must be serializable" again.

But anyway, everyone knows that serialization is far from perfect.

On-topic again:
I think it's useless and bizarre that there is a difference between
val list: Serializable = List(1)
and
val list: Serializable = ::(1, Nil)
.
Really, what's the point of rejecting the first and allowing the second one? Which benefit does the user have from that?`Which grave mistakes have been prevented?

Aleksey Nikiforov

unread,
Apr 20, 2013, 9:32:26 PM4/20/13
to scala-l...@googlegroups.com
The bottom line is: the only correct way to use Serializable is to indicate to JVM that a class can be serialized, and any other use of it is incorrect. So the question of what interfaces should extend Serializable is moot, since you should never require Serializable as a type anywhere outside ObjectOutputStream.

martin odersky

unread,
Apr 21, 2013, 10:05:19 AM4/21/13
to scala-l...@googlegroups.com
As everyone has argued on this List, serializable as a static property is utterly broken. So why waste more cycles discussing its subtleties? Given that it is broken I can predict that _any_ change will cause another inconsistency and we end up debating endlessly about nothing.

Cheers

 - Martin

Simon Ochsenreither

unread,
Apr 21, 2013, 4:44:11 PM4/21/13
to scala-l...@googlegroups.com
Hi,


As everyone has argued on this List, serializable as a static property is utterly broken.

I don't think anyone is disagreeing with that in general.

 
So why waste more cycles discussing its subtleties?

My intention is to get rid of these subtleties, which in this limited case is an achievable goal, so that users don't have to deal with these subtleties anymore.
I agree that in general Serializable shouldn't be mandated by an interface, but in this case, "sealed abstract class List" is just an implementation detail of the way GADT's are encoded in Scala and not an interface in the general sense. (I assume that everyone agrees that properties shared by all subtypes should be pushed up to the common supertype, especially if it is sealed, right?)

 
Given that it is broken I can predict that _any_ change will cause another inconsistency and we end up debating endlessly about nothing.

Considering the two points I brought up:
  • Pushing an interface to a superclass is compatible change as far as I remember.
  • Independently of that, why do we even care about introducing another layer of inconsistencies by introducing another Serializable instead of aliasing to the existing one, if everyone agrees that it is broken in the first case? The same applies to Cloneable.
Let's see what the test suite says.

Bye,

Simon

Simon Ochsenreither

unread,
Apr 21, 2013, 7:19:56 PM4/21/13
to scala-l...@googlegroups.com
Forget about the second point, at least for Serializable, looks like scalac already does some magic with it.

Considering the first point:

I'll let everyone decide for himself, which "subtlety" he prefers:

List(List(), Vector())

Version 1:

List[scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def companion:
 scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq{def dropRight(n: Int): scala.collection.immutable.Seq[Any] with
 scala.collection.AbstractSeq[Any]; def takeRight(n: Int): scala.collection.immutable.Seq[Any] with
 scala.collection.AbstractSeq[Any]; def drop(n: Int): scala.collection.immutable.Seq[Any] with
 scala.collection.AbstractSeq[Any]; def take(n: Int): scala.collection.immutable.Seq[Any] with
 scala.collection.AbstractSeq[Any]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[Any]
 with scala.collection.AbstractSeq[Any]}]; def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def drop(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]
 {def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def splitAt(n: Int): (scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing], scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing])}; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def drop(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]
 {def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def splitAt(n: Int): (scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing], scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing])}; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]{def companion:
 scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def drop(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]
 {def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def splitAt(n: Int): (scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing], scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing])}; def take(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]{def companion:
 scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def drop(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]
 {def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def splitAt(n: Int): (scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing], scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing])}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with
 scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def drop(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]};
 def take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]
 {def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def slice(from: Int,until: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}; def splitAt(n: Int): (scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing], scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing])}; def splitAt(n: Int):
 (scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def
 dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n:
 Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 take(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing];
 def slice(from: Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]}, scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def
 takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collection.immutable.Seq[Nothing]
 with scala.collection.AbstractSeq[Nothing]; def take(n: Int):
 scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def slice(from:
 Int,until: Int): scala.collection.immutable.Seq[Nothing] with
 scala.collection.AbstractSeq[Nothing]})}]


Version 2:

List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing] with java.io.Serializable]

Bye,

Simon

Paul Phillips

unread,
Apr 21, 2013, 8:26:10 PM4/21/13
to scala-l...@googlegroups.com

On Sun, Apr 21, 2013 at 4:19 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
I'll let everyone decide for himself, which "subtlety" he prefers:

List(List(), Vector())

Not exactly cricket there, bud. You are as far as I know the person to have discovered that the difference in Serializable parentage is the trigger for that particular pathology. I certainly didn't know it, and I've spent a long time with that one. So it's not as if anyone's position was "So pure is my love for these ridiculous lubs, List must never change."


Simon Ochsenreither

unread,
Apr 22, 2013, 4:43:00 AM4/22/13
to scala-l...@googlegroups.com
Stream seems to suffer from the same issue. Even worse, Stream is not sealed!

I wonder what's the use-case of allowing the user to supply his/her own Stream subclasses? Looking at the code, I think it is likely that the Stream will behave inconsistently/break if the supplied subclass of Stream is not Stream.Empty or Stream.Cons.

Paul Phillips

unread,
Apr 22, 2013, 1:49:14 PM4/22/13
to scala-l...@googlegroups.com

On Mon, Apr 22, 2013 at 1:43 AM, Simon Ochsenreither <simon.och...@gmail.com> wrote:
I wonder what's the use-case of allowing the user to supply his/her own Stream subclasses?

There isn't one that I'm aware of, it should be a bug. I looked at the history for any evidence to the contrary, didn't see anything obvious. A walk down memory lane follows. It looks like "throw" used to be a member on Throwable in some fashion.

 Author: Martin Odersky <ode...@gmail.com>
 Date:   Fri Feb 14 05:36:31 2003
 
     Initial version.

package scala;

trait Stream[a] {

  def isEmpty: Boolean;
  def head: a;
  def tail: Stream[a];

  protected def error[a](x: String):a = (new java.lang.RuntimeException(x)).throw;

  def length: Int = if (isEmpty) 0 else tail.length + 1;

  def append(def rest: Stream[a]): Stream[a] =
    if (isEmpty) rest
    else ConsStream(head, tail.append(rest));

  def init: Stream[a] =
    if (isEmpty) error("EmptyStream.init")
    else if (tail.isEmpty) new EmptyStream[a]()
    else ConsStream(head, tail.init);

  def last: a =
    if (isEmpty) error("EmptyStream.last")
    else if (tail.isEmpty) head
    else tail.last;

  def takeWhile(p: a => Boolean): Stream[a] =
    if (isEmpty || !p(head)) new EmptyStream[a]()
    else ConsStream(head, tail.takeWhile(p));

  def dropWhile(p: a => Boolean): Stream[a] =
    if (isEmpty || !p(head)) this
    else tail.dropWhile(p);

  def take(n: Int): Stream[a] =
    if (n == 0) new EmptyStream[a]()
    else ConsStream(head, tail.take(n-1));

  def drop(n: Int): Stream[a] =
    if (n == 0) this
    else tail.drop(n-1);

  def at(n: Int) = drop(n).head;

  def map[b](f: a => b): Stream[b] =
    if (isEmpty) new EmptyStream[b]()
    else ConsStream(f(head), tail.map(f));

  def foreach(f: a => Unit): Unit =
    if (isEmpty) {}
    else { f(head); tail.foreach(f) }

  def filter(p: a => Boolean): Stream[a] =
    if (isEmpty) this
    else if (p(head)) ConsStream(head, tail.filter(p))
    else tail.filter(p);

  def forall(p: a => Boolean): Boolean =
    isEmpty || (p(head) && tail.forall(p));

  def exists(p: a => Boolean): Boolean =
    !isEmpty && (p(head) || tail.exists(p));

  // the next four functions are obsolete!

  def reduce(op: (a, a) => a): a =
    if (isEmpty) error("reduce of empty stream")
    else tail.fold(op)(head);

  def reduceRight(op: (a, a) => a): a =
    if (isEmpty) error("reduce of empty stream")
    else if (tail.isEmpty) head
    else op(head, tail.reduceRight(op));

  def fold[b](op: (b, a) => b)(z: b): b =
    if (isEmpty) z
    else tail.fold(op)(op(z, head));

  def foldRight[b](op: (a, b) => b)(z: b): b =
    if (isEmpty) z
    else op(head, tail.foldRight(op)(z));

  def flatMap[b](f: a => Stream[b]): Stream[b] =
    if (isEmpty) new EmptyStream[b]()
    else f(head).append(tail.flatMap(f));

  def reverse: Stream[a] = {
    def snoc(xs: Stream[a], x: a): Stream[a] = ConsStream(x, xs);
    fold(snoc)(new EmptyStream[a]())
  }

  // The following method is not compilable without run-time type
  // information. It should therefore be left commented-out for
  // now.
  //       def toArray: Array[a] = {
  //         val xs = new Array[a](length);
  //         copyToArray(xs, 0);
  //         xs
  //       }

  def copyToArray(xs: Array[a], start: Int): Int = {
    xs(start) = head;
    tail.copyToArray(xs, start + 1)
  }

  def zip[b](that: Stream[b]): Stream[[a, b]] =
    if (this.isEmpty || that.isEmpty) new EmptyStream[[a, b]]()
    else ConsStream([this.head, that.head], this.tail.zip(that.tail));

  def print: Unit =
    if (isEmpty) System.out.println("EmptyStream")
    else {
      System.out.print(head as java.lang.Object);
      System.out.print(", ");
      tail.print
    }
}

Simon Ochsenreither

unread,
Apr 22, 2013, 3:59:29 PM4/22/13
to scala-l...@googlegroups.com
Forgot to link the issues to this thread and this thread to the issues. :-/

Here they are:

Interestingly, the large types only started to appear with 2.10, I checked 2.9.3 and I got the “small” type with that version even though List didn't implement Serialization back then, too.

Paul Phillips

unread,
Apr 22, 2013, 5:29:08 PM4/22/13
to scala-l...@googlegroups.com
On Mon, Apr 22, 2013 at 12:59 PM, Simon Ochsenreither <simon.och...@gmail.com> wrote:

Interestingly, the large types only started to appear with 2.10, I checked 2.9.3 and I got the “small” type with that version even though List didn't implement Serialization back then, too.

As adriaan said in the ticket, it is not Serializable per se which is relevant, but the difference in class parentage.

Simon Ochsenreither

unread,
Apr 22, 2013, 5:39:37 PM4/22/13
to scala-l...@googlegroups.com

As adriaan said in the ticket, it is not Serializable per se which is relevant, but the difference in class parentage.

Yes, I understand. I wouldn't add Serializable if the sole reason were to make the types prettier.
Reply all
Reply to author
Forward
0 new messages