> > > At this point, I'm sort of getting an insight
> > > into why dynamic language proponents claim typing
> > > restricts them even though I've not been previously
> > > sympathetic in any way...
> >
> > I don't follow. You've started going down this path to
> > explore abstract type members and path dependent types.
> > It's an interesting and sometimes useful approach to
> > o things. But it's not always the right answer. If
> > abstract type members aren't the right answer (and
> frankly
> > I rarely use them) then don't use them. Use something
> > else.
>
> let me clarify a bit. I'm not criticising Scala's type
> system per se. It seems very powerful and I can't really
> critique it as I literally understand 10% of it. i guess
> i just had a brief insight into the lengths to which it is
> sometimes necessary to delve into and understand the type
> system in order to express something in Scala which I have
> otherwise found intuitive in other languages (despite them
> being unsound). This type of expertise in type systems is
> not required with dynamic typing, although clearly this
> has severe disadvantages with regard to checking and
> refactoring.
>
I think that's a reasoned way to look at it. There's no free lunch. Dynamic typing can indeed remove some complexity and bulk from your code, but in exchange complexity pops up elsewhere, such as needing to write more tests, less assurance when refactoring, less clarity when trying to figure out what you can count on about the types or services offered by objects being passed to a method, etc.. Static typing lets gives you deterministic refactoring, documentation about the types being passed to methods, eliminates the need to write tests for things caught by the type system, etc., but in exchange you have to learn and deal with a more complex type system compared to the dynamic languages and write a bit more code. (A bit more in Scala. In Java, you have to write a lot more code, but that isn't really static typing's fault.)
> > If you want static checking then maybe "generic" type
> > parameters are the right answer. In fact, I think that
> > until there's a larger body of experience with path
> > dependent types, the default solution to most such
> "real"
> > static typing problems should be type parameters.
>
> Yes, sure, i'd tend to use generics also. I guess I was
> just following a path of thought from the Scala book.
> I've also been influenced somewhat by Beta perhaps, which
> h has no generics and instead uses virtual patterns (path
> dependent types, I guess) to express this type of
> flexibility.
>
I also tend to use generics. It may be because I come from Java and that's what I'm used to, but they seem easier for me to think about.
> > And if static checking isn't the right answer and you
> want
> > to dynamically check compatible skiers or currency or
> > whatever, Scala gives powerful tools for that as well.
> > You can use OO style polymorphism or pattern matching,
> or
> > r both.
>
> Sure.
>
> > Finally, I want to point out that Scala has an escape
> > mechanism in its type system. You can cast anything to
> > anything at anytime. That's a big gaping hole as far
> as
> > type systems are concerned, but a pragmatic and useful
> > choice sometimes.
>
> Hmm, that is interesting. And without wishing to be
> flippant, I think the presence of that "hole" would be
> very important in some programs. I expect there will
> always be things that are difficult or impossible to
> express in a practical type system.
>
Well first there's pattern matching, which effectively does safe casts for you. Martin doesn't like calling this a cast though. In Scala jargon, "cast" means unsafe cast from the statically provable perspective. And in Scala you can pretty much cast anything to anything. Even things that could be statically known to be sure to fail at runtime are allowed, if I'm remembering correctly. I think Java will catch these as compiler errors. So casting with asInstanceOf is very much discouraged in Scala, but it is there when you need it.
In ScalaTest I have used it on several occasions. I did a grep to see why. Looks like I primarily use it when I'm using Java reflection:
Macintosh-10:scalatest bv$ fgrep asInstanceOf *.scala
Assertions.scala: case Some(e) => e.asInstanceOf[T] // I know this cast will succeed, becuase iSAssignableFrom succeeded above
Assertions.scala: case Some(e) => e.asInstanceOf[T] // I know this cast will succeed, becuase iSAssignableFrom succeeded above
Assertions.scala: val clazz = manifest.erasure.asInstanceOf[Class[T]]
Assertions.scala: case Some(e) => e.asInstanceOf[T] // I know this cast will succeed, becuase iSAssignableFrom succeeded above
Assertions.scala: "hi".asInstanceOf[T]
PrivateMethodTester.scala: for ((arg, paramType) <- zipped if !paramType.isAssignableFrom(arg.asInstanceOf[AnyRef].getClass)) yield arg
PrivateMethodTester.scala: case anyVal: AnyVal => anyVal.asInstanceOf[AnyRef]
PrivateMethodTester.scala: privateMethodToInvoke.invoke(target, anyRefArgs.toArray: _*).asInstanceOf[T]
SuiteRerunner.scala: val suite = suiteClass.newInstance().asInstanceOf[Suite]
TestRerunner.scala: val suite = suiteClass.newInstance.asInstanceOf[Suite]