Article Discussion
The Origins of Scala
Summary: Martin Odersky talks with Bill Venners about the history that led to the creation of the Scala programming language.
77 posts on 6 pages.      
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: May 21, 2009 4:21 AM by
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 0:33 PM      
> He never said it was about covariance being simpler or easier to understand

that's not my understanding of Mr Meyers position. from http://se.ethz.ch/~meyer/ongoing/covariance/recast.pdf , which admittedly only has him as a coauthor:

"The cats-and-boats example is not contrived. It is typical of a common scheme:
covariant redefinition of the type of a query (usually an attribute, but possibly a
function) such as captain. The very first case of inheritance that many people see in
elementary presentations tends to be (see e.g. [16]) something like a class MAMMAL
inheriting from ANIMAL; if there is a query offspring, then its type should be
redefined covariantly throughout, reflecting that the offspring of a mammal are
mammals, not just animals."

So, it appears to me as an intuition and expressiveness issue.
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 0:35 PM      
and further from the same paper of Bertrand's:

"The earlier discussions, and everyday examples, suggest that “the world is
covariant”. In particular allowing covariant results but disallowing covariant
arguments mean that we can’t associate setter procedures (such as sail or engender)
with queries, or write object comparison functions such as is_equal with proper type
signatures. Regrettably in light of its mathematical elegance, this scheme (contravariance) seems to
have little practical applicability."
Bill
Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
Re: The Origins of Scala
May 5, 2009 0:49 PM      
Hi James,

> > Yes, I'm sure he meant that too. Remember this was
> 1997.
> > What contravariance doesn't help you do is keep Girls
> and
> > Boys in separate rooms.
>
> I'm at a disadvantage here in that I don't have the full
> text but the first line in what you quote is:
>
> "With contravariance one would not have these problems"
> which seems to suggest that it does solve the problem of
> keeping the boys and girls in separate rooms. Maybe I'm
> misunderstanding but I thought the boy and girl skier
> example was meant to show the problem with covariance and
> then the following text was meant to argue that despite
> these types of problems, covariance is still the right
> choice.
>
Sorry, let me clarify. Meyer was pointing out that although covariance has a type soundness problem, it achieves his goal of modeling the use case of Skiers, Boys, Girls, and Rooms. He then points out that although contravariance does not have the type problem, contravariance doesn't let him model the use case of Skiers, Boys, Girls, and Rooms. He also goes further to say he doesn't know of any use cases that contravariance actually helps you implement. And then says that in a nod to the practical, he made type parameters covariant so he could support this kind of use case even though it has a type soundness hole.
Martin
Posts: 15 / Nickname: modersky / Registered: September 14, 2003 9:46 PM
Re: The Origins of Scala
May 5, 2009 1:04 PM      
> > > There's a big difference between a physical law that
> > has
> > > been confirmed innumerable times and the
> > recommendations
> > > of computer scientists to programmers.
> > >
> > You mean, logic is a recommendation by computer
> scientists
> > to programmers?
>
> No. I didn't say anything like that.
>
> > > "It's disgusting"? That's a bit over the top, don't
> > you
> > > think?
> > >
> > Frankly I have to side with James there. These
> discussions
> > of academic vs practical are silly and annoying (and
> > particularly funny in the context of Scala, since
> people
> > seem to just disregard who's behind the language and
> what
> > their practical credentials are).
>
> Since when are 'silly' and 'annoying' synonyms for
> 'disgusting'?
>
> If you are saying that people must believe whatever those
> with the proper credentials say, then I reject that
> outright. The lack of a piece of paper is not the lack of
> intelligence, ability or knowledge.
>
> > We are doing ourselves a disservice as a field with
> these
> > allusions. Engineering is defined as the application of
> > science to a technical problem. If we feel it's cool to
> > disregard or doubt science in computing we put
> ourselves
> > on the same level as simple technicians, and we should
> not
> > complain if we will in the future be paid on this
> level.
>
> Language design is not a science. I studied Physics
> before I studied computer science and computer science is
> more like mathematics than it is like a hard science.
> Science requires falsifiable hypothesis. Logic is not
> t science. If you feel you can propose such a hypothesis
> I'm open to it.

Well, for me logic and mathematics is a science, it's just not a natural science. And it's the only candidate discipline to underly our field of software engineering (maybe some people see that field rooted in social sciences, but I would have my doubts). As to falsifiable hypothesis: I would say, ``immutable datastructures can always be covariant'' (that's what you stated) is such a falsifiable hypothesis. That's not a matter of belief.

Belief is: does it matter? Should I care in my work? But that's just the same as for Ohm's law. There are gifted electricians who do not care for Ohm's law; they just cobble their circuits together guided by experience and intuition. They might do great work. But they are not engineers. So for that reason I thought James' analogy was right on spot.
Martin
Posts: 15 / Nickname: modersky / Registered: September 14, 2003 9:46 PM
Re: The Origins of Scala
May 5, 2009 1:22 PM      
The Eiffel example is very instructive. In the end, we want our types to model interesting properties of the application domain as faithfully as possible. Given our current knowledge, this is hard. Often, there's a temptation to give up, and just do a convenient shortcut, as in Eiffel covariance or Java arrays. But I fear that everytime one does this, it has really bad long-term consequences. I have experienced that first hand for Java arrays and suspect that Eiffel has suffered the same.

I do not advocate at all to ignore the needs of practical modelling. It's precisely this tension between modelling needs and logic which is fruitful in the long run. As an example, I claim that Scala has solved Eiffel's covariance problems by the introduction of abstract type members. If we had swept the problem under the carpet by adopting unsound rules, we would never have found the right solution.
Bill
Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
Re: The Origins of Scala
May 5, 2009 1:33 PM      
> yes, it's easy to make up a scenario where parameter
> covariance leads to runtime holes. whether it is a major
> problem in practice is another question.
>
Yes, I think its the same question with respect to covariance of arrays in Java. It is type unsound, but relatively rare that people get ArrayStoreExceptions in practice. They do get them occasionally, though.

> > contravariance is of essentially no practical use.
>
> I'd agree with bertrand here. I've found contravariance
> of input parameters to be useless. covariance is
> statically unsound, and therefore the java position of
> invariance seems sensible in a record type model.
> (Obviously contravariance of return types is a different
> t story)
>
I turned out to need contravariance in ScalaTest matchers design, but it is really also an example of function parameters being contravariant, because in ScalaTest a matcher is a function. Users don't really need to worry about it, or understand why it is contravariant. They just know that things they try that they think should work turn out to work as expected. If you're interested, I put some info on it in this page (search for variance):

http://www.artima.com/scalatest/doc-0.9.5/org/scalatest/matchers/Matcher.html

> > In computing science as in other disciplines, it is
> after
> > all much easier to device drastically simple theories
> if
> > we neglect to make them agree with reality.
>
> we just spend so much time trying to form the perfect type
> system that I wonder if it would be better to accept
> occasional holes for simplicity and clarity. It's the old
> 80/20 rule. To me Bertrand's crazy example sort of makes
> sense. You have a boy skier and a girl skier and they
> can't share a room. However, if you just tell someone you
> have 2 skiers and to put them in a room together, and you
> do it, someone's going to get in trouble ;-)
>
I'd put the question slightly differently. Thinking about how to form the perfect type system is what academics are paid to do, and that's a worthy endeavor. Martin has come up with a pretty nice type system in Scala. The question I'd ask is whether the benefit offered by the type system is worth the cost of learning, understanding, and dealing with that type system. Also, what are the real benefits, and what are the real costs in practice?

> fair enough. i find it simpler then to understand from a
> modeling perspective. for instance, if you have a Java
> class animal:
>
> class Animal { void eat(Food f) {}}
>
> and you want to subclass it to make Bear, you'd ideally
> want:
>
> class Bear extends Animal { void eat (Honey h) {} }
>
> where eat is overridden and Honey is a subclass of Food.
> To me this makes modeling sense, even though we can then
> n ask the question as to what happens if we feed a bear
> weetabix...
>
That's funny. In Programming in Scala we use this example, and show that covariant method parameters would lead to the abhorrent notion that you could feed fish to cows!

> yes, you do it the same sort of way in Beta with virtual
> patterns. In Beta you still have type holes because the
> Boy and Girl would still be subclasses of Skier.
>
> So, in your scala example, does it mean that Boy and Girl
> are no longer subclasses of skier? if they are, what
> happens if you call Skier::share() on a boy as a Skier and
> pass in a girl as a Skier?
>
Oops. I wondered why I got the wrong compiler error. My example was full of bugs. I forgot to make Boy and Girl extend Skier, and forgot to put an explicit type on s. Here's what I meant:


abstract class Skier {
type SuitableRoommate <: Skier
def share(other: SuitableRoommate)
}

class Boy extends Skier {
type SuitableRoommate = Boy
override def share(other: Boy) {}
}

class Girl extends Skier {
type SuitableRoommate = Girl
override def share(other: Girl) {}
}

scala> :load skier.scala
Loading skier.scala...
defined class Skier
defined class Boy
defined class Girl

scala> val s: Skier = new Boy
s: Skier = Boy@101afe

scala> val g = new Girl
g: Girl = Girl@cf63bb

scala> s.share(g)
<console>:10: error: type mismatch;
found : Girl
required: s.SuitableRoommate
s.share(g)
^


> So, the idea of putting the share() function in the base
> class must be so that Boy and Girl can be treated
> polymorphically from the perspective of the share() method
> at some point, surely? otherwise, why wouldn't you just
> omit it from the Skier base and just place share(Girl) on
> the Girl class and vice versa?
>
Yes, that's the point. Share is still in there on the base class.

> And if Boy and Girl are no longer substitutable for Skier,
> then haven't we lost something major?
>
> Alternatively, i'm not understanding how Scala handles
> this.
>
Scala has something called path-dependent types, which means the actual type depends on the path you take to get to it. It highlights that objects actually do have members that are types. The type error is that they got a Girl where an s.SuitableRoommate was needed. The Scala compiler somehow keeps track that the object referenced by s, its type member is a Boy. So when you try to pass a Girl in there, you get the type error.
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 1:35 PM      
> As an example, I claim that Scala has solved Eiffel's covariance
> problems by the introduction of abstract type members.

I must be missing something.

Given that Scala Boys and Girls are no longer subclasses of Skier, how do I write a function which can treat Boys and Girls as Skiers in Scala, thereby retaining the spirit of the original model?

i.e. def test(s: Skier) { println(s) }

Is there a type marking to put on the input parameter to indicate that it can accept covariant extensions to Skier?
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 1:37 PM      
> Given that Scala Boys and Girls are no longer subclasses
> of Skier, how do I write a function which can treat Boys
> and Girls as Skiers in Scala, thereby retaining the spirit
> of the original model?

ignore this, bill just answered my question as i posted!

cheers,
Andrew
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 1:50 PM      
> I claim that Scala has solved Eiffel's covariance
> problems by the introduction of abstract type members.

yes, i can see it is very powerful and resolves the type errors that I used to get in languages like Beta.

One question however: is it possible given Bill's Girl/Boy classes to write a function which takes 2 Skiers and makes them share a room, such that it works for 2 Boys or 2 Girls?

i.e. my first attempt doesn't compile:

def test[T <: Skier](s1: T, s2: T) { s1.share(s2) }

Cheers,
Andrew
Mark
Posts: 48 / Nickname: mthornton / Registered: October 16, 2005 11:22 PM
Re: The Origins of Scala
May 5, 2009 2:21 PM      
> That's funny. In Programming in Scala we use this example,
> and show that covariant method parameters would lead to
> the abhorrent notion that you could feed fish to cows!

The rather unfunny truth is that many animal products (including fish) really have been fed to cows. The consequences of this practice have been very expensive, especially here in the UK. So perhaps covariance models reality more accurately than you might have expected!
James
Posts: 11 / Nickname: jiry / Registered: November 15, 2007 2:29 AM
Re: The Origins of Scala
May 5, 2009 2:30 PM      
> One question however: is it possible given Bill's Girl/Boy
> classes to write a function which takes 2 Skiers and makes
> them share a room, such that it works for 2 Boys or 2
> Girls?
>
> i.e. my first attempt doesn't compile:
>
> def test[T <: Skier](s1: T, s2: T) { s1.share(s2) }


def test(s1 : Skier)(s2 : s1.SuitableRoommate) = s1 share s2

If you don't write it in curried form Scala complains about an illegal dependent method type. I'm not sure why. I tested this using the 2.7.4 compiler.
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 2:33 PM      
> def test(s1 : Skier)(s2 : s1.SuitableRoommate) = s1 share s2
>
> If you don't write it in curried form Scala complains
> about an illegal dependent method type. I'm not sure why.
> I tested this using the 2.7.4 compiler.

thanks james. yes, i got the illegal dependent type error also when I used the non-curried form also. In fact, I didn't know that it was possible to use a curried form ;-)

Andrew
Bill
Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
Re: The Origins of Scala
May 5, 2009 2:39 PM      
Hi Andrew,

> > I claim that Scala has solved Eiffel's covariance
> > problems by the introduction of abstract type members.
>
> yes, i can see it is very powerful and resolves the type
> errors that I used to get in languages like Beta.
>
> One question however: is it possible given Bill's Girl/Boy
> classes to write a function which takes 2 Skiers and makes
> them share a room, such that it works for 2 Boys or 2
> Girls?
>
> i.e. my first attempt doesn't compile:
>
> def test[T <: Skier](s1: T, s2: T) { s1.share(s2) }
>
Well one trouble with this attempt is that it isn't defined in Skier that the type of SuitableRoommate will always be the outer type. This is possible for example:


class Cat extends Skier {
type SuitableRoommate = Dog
override def share(other: Dog) {}
}

class Dog extends Skier {
type SuitableRoommate = Cat
override def share(other: Cat) {}
}


More generally, the compiler has to check the path dependent types at compile time, so it must base them on the type of the variable. What that means you can't do with Scala's abstract type approach that you can do (without safety) with Eiffel's covariant method parameters is pass either a Boy to a Skier that will happen to be a Boy at runtime. For example:


scala> val s: Skier = new Boy
s: Skier = Boy@995b29

scala> val g = new Girl
g: Girl = Girl@7aaee9

scala> val b = new Boy
b: Boy = Boy@43c919

scala> s.share(b)
<console>:9: error: type mismatch;
found : Boy
required: s.SuitableRoommate
s.share(b)
^

scala> s.share(g)
<console>:10: error: type mismatch;
found : Girl
required: s.SuitableRoommate
s.share(g)
^

scala> b.share(b)

scala> b.share(g)
<console>:10: error: type mismatch;
found : Girl
required: b.SuitableRoommate
b.share(g)
^

scala> g.share(g)

scala> g.share(b)
<console>:10: error: type mismatch;
found : Boy
required: g.SuitableRoommate
g.share(b)
^


So a Girl can share a room with a Girl, and a Boy with a Boy, and a Girl can't share a room with a Boy, nor can a Boy share a room with a Girl, but a Boy held from a Skier reference can also not share a room with a Boy. I think that may be what you'll run up against if you try to make a method like you're talking about. However I'm not convinced there isn't a way to do it until I try. I don't have time to try it now but later I'll see if I can come up with a solution.
Andrew
Posts: 18 / Nickname: 55548 / Registered: May 16, 2008 6:33 AM
Re: The Origins of Scala
May 5, 2009 3:08 PM      
> What that means you can't do with Scala's abstract type approach that you can do
> (without safety) with Eiffel's covariant method parameters
> is pass either a Boy to a Skier that will happen to be a
> Boy at runtime.

i'm sure there has to be a way. otherwise, it would restrict the type of framework-like code you could write in scala where abstract types were used? or perhaps there's another way using generic type parameters?

for example, how would you create a single method that took a list of either boys or girls and arranged it so that everyone in the list was sharing a room, without duplicating the code for boys and girls separately?
Morgan
Posts: 37 / Nickname: miata71 / Registered: March 29, 2006 6:09 AM
Re: The Origins of Scala
May 5, 2009 3:29 PM      
Has anybody noticed that all Artima discussions degenerate into debates over Java generics? :-)

For the record, I think Meyer's example is, ultimately, poor. There are lots of reasons for Skiers not to room together other than sex. Does he propose to add AntiSmokingZealotGirl and LazySlobSmokingBoy subclasses? No, all skiers (or a superclass, Person) should have something like a canRoomWith(Skier other) method.

Use the classes to prevent Skiers from rooming with Skis and Avalanches.
77 posts on 6 pages.