3 ms·
Having never used Scala before, does its type system provide details about errors that other languages do not? Watching a compile fail because of an incorrect t
by randomdata 13y ago
Having never used Scala before, does its type system provide details about errors that other languages do not? Watching a compile fail because of an incorrect type is not something I have run into very often, if ever, in other languages that provide similar type systems.
I mean mistakes can happen and if the type system can catch it for free, so to speak, that is great. I'm not about to argue that it is completely useless. But in terms of probabilities of what kind of bugs might be introduced, type errors seem to be on the low end.
To infer that Scala's type system is powerful enough to catch the more common types of mistakes programmers make, that is quite an impressive claim. I am curious to know more.
- jacobgreenleaf 13y agoIn Haskell, and I assume Scala, you can name types of the same form, so I might say a TimeSeries is a list of floating point values. If I use that data type, you can't accidentally pass a different kind of list of floating points even though they're the same type.
- p4lindromica 13y agoYes, you can do this in scala with type aliases
- lmm 13y agoType aliases don't solve that problem. You need to use something like Shapeless' newtype.
- kasey_junk 13y agoType aliases do not solve this. The closest you can get is using the new value classes & those have some very big caveats
- yummyfajitas 13y agoA simple example: consider scalaz's NonEmptyList[T] class, which turns a failure to populate a list into a compile error rather than a runtime error. A more complicated example. In one scala system I worked on we had a master/slave postgres db system. We were replacing a legacy RoR system with a Scala system, and in the RoR system there were all sorts of data inconsistency errors caused by people writing to master and reading from the slaves before replication occurred. In the Scala system which replaced it, we set up a monadic action system. A function which hit the database would have a type signature either PReader[T] or PWriter[T] - this was the only way to access a java.sql.Connection short of manually calling jdbc. Combining the two forms yields a PWriter: for { _ <- putObjectToDB(args) obj <- getObjectFromDB(args) yield (render(obj)) // is a PWriter[_] The whole operation runs in a single transaction against the correct database, and any attempt to do the wrong thing is a compile error.
- lmm 13y agoIt's partly culture; Scala makes types that little bit easier to use (e.g. case classes, type inference), so things that you might pass as an untyped Map[String, Object] in other languages, you tend to pass as a case class instead. e.g. using spray in scala, the type system will catch if you misspell a HTTP header, because, as the article complains about, they're represented as types. (Though of course there is an escape hatch, you can use RawHeader(name, value) if you need to).
- dancapo 13y agoScala has dependent type support, so, yes, it is quite more powerful than most languages in widespread use. You can look at the Shapeless library to see that at work. However, that is not really what's going on... though Scala type system, even without dependent types, is strictly more powerful that Java's, it really comes down to the ease of use: Scala programmers tend to use types liberally (which was one of the criticisms of the article), and that is part of the "magic". Part of this is how easy it is to define a type: it can be as short as a single line. So you'll see way less String types in Scala, for instance, or "one type to do it all" like the article wanted for HTTP. Instead, you get many types, in which invalid states are not possible and, therefore, getting the types right is enough to ensure there are no invalid states. Likewise, the partial type inference offered by Scala makes it possible to not worry about all these types: the compiler knows what type you got, and knows whether it can be used the way you are using it, so you don't have to keep looking up types to get things accomplished, but still get to have the types. Another part is that Scala support higher order types, something not supported by Java, which makes them more useful. That's what allows monads & companions come in and make an appearance -- it's not that you can't write a monad in Java, it's just that you can't abstract over them. The final part is emphasis on immutability. When you stick to immutable objects representing valid states, the space for errors not caught by the type system is greatly reduced. Let's get back to the headers, then. First, yes, you are allowed to add arbitrary headers (which is supported by Spray through RawHeader, something it took me 30 seconds to find out, even though I have never used Spray and have little familiarity with it), but section 14 of RFC 2616 has a nice list of standard headers and the rules they are expected to abide by, so let's have them. And if you have a header, and it is a X-Forwarded-For, isn't it reasonable to expect the value to be a valid remote address? It is supposed to be a valid remote address, after all. So, if you ask for this header, should you simply get a string that may or may not be actually valid, or should the type system give you an Option that may contain Some valid header, or None, therefore ensuring that you don't just assume you are getting the right thing? And if you get something and retrieve the value, is it preferable to just get a string, that might lead to some ad hoc parsing of the address, or some actual type where you can easily retrieve information in a safe manner? The Scala community will usually think that yes, that's a good idea, and design the APIs accordingly.