Java.next() - Scala: The Revenge of the Static Typing
batsov.com
batsov.com
He said that metaprogramming is hard. The area of metaprogramming is partially covered by higher-order functions. The coverage is big, in my opinion, I haven't missed metaprogramming in Haskell for ten years, at least (I missed it for first two weeks with Haskell).
He also said that there's no mechanism to compensate for the absence of duck typing. In Haskell, at least, there are type classes which allow you to make your types as duck as you would wish, maybe slightly less. I think that some Scala mechanisms provide that power.
I think that type classes are the way to go.
Duck typing is mostly popular because multiple inheritance sucks, and because inherting a class to only overload a method sucks.
Languages like Ruby, Python or Perl are so popular because they are less verbose than Java or C++, with the disadvantage, that the compiler can't help you that much.
Haskell is a language that combines the advantages, less verbosity with a helping compiler, and a static type system that rocks.
However, can you clarify why you would argue for type classes over duck/structural typing? You indicate that 'type classes are the way to go' but don't explain why.
Scala of course does have a form of Type Classes and while they tend to be what I reach for more often than Structural Types in Scala, it doesn't obviate Structural Types completely and I'd be interested in analysis of the diffs.
Like kscaldef said, you know at compiletime if something can quack, and the overhead for doing this is quite small.
Haskell: instance Quacker MySpecialDuck where quack = "qqquuuuuuaaaaaakkkkk"
"Scala of course does have a form of Type Classes and while they tend to be what I reach for more often than Structural Types in Scala, it doesn't obviate Structural Types completely and I'd be interested in analysis of the diffs."
In which cases do you need duck typing? Adding dynamically a method to a class?
But that may be orthogonal to static/dynamic typing (e.g. scala 2.9 has this ability, and javascript doesn't)
Whereas, in reality, there's a whole class of static type systems which do the same thing, except statically: structural type systems (example: OCaml's object types).
Much as duck typing, they only make sense for object-oriented languages. Structural type systems treat (concrete) objects and object types as method sets (where a method is a triple of name, argument types and return types), where, given the types A and B with A a structural subtype of B, A's methodset will be a superset B's methodset.
> I think that some Scala mechanisms provide that power.
Scala provides structural types (via type refinements) since 2.6.0: http://programming-scala.labs.oreilly.com/ch12.html#Structur... http://scala.sygneca.com/patterns/duck-typing-done-right
And all the articles about Scala are missing one important detail -- structural typing and type inference are not a replacement for dynamic typing and all evidence to the contrary I've seen are extremely shallow.
Truth of the matter is the choice between static and dynamic comes down to personal style and individual use-cases for which one or the other is better.
I think that the path forward for programming will see a convergence between static and dynamic typing, but the amount of static analysis that programmers do will only increase. Certain dynamic practices such as name binding at runtime will fall out of favor, because that practice hampers static analysis. On the other hand, static type systems in use will probably become more flexible, simultaneously increasing the things that they let you automatically track while decreasing the things that the force you to track.
Time will tell, I suppose.
they cover 80% of the use-cases
No they don't, it's actually the other way around -- try recreating Rails in Scala.For that matter, give me an ORM written in Scala that's both (a) stable and consistent + (b) usable without me having to bash my head against the keyboard.
The reason why you cannot recreate a Rails clone is because Rails works basically by redefining everything at runtime, over and over again ... the whole Ruby language is built from the ground up on redefining classes (for the "class" construct, defining new classes in case they don't exist, that's just a side-effect). I'm not saying you cannot build something better in Scala (time will tell), but that something has to be a lot different and a lot more effort will be required.
Yeah, you can do "var a = 1" in Scala, that's nice.
the path forward for programming will see
a convergence between static and dynamic typing
Actually the path IMHO is a bigger separation between static and dynamic, with optional static types introduced in dynamic languages as hints for performance purposes.Basically that's because OOP is inherently incompatible with static types and because type classes are inherently incompatible with dynamic types.
Why do you say that optional static typing introduced into dynamic languages is a divergence? Coupled with looser typing from the static languages, that looks like convergence to me. And what part of OOP do you see as incompatible with typing?
Dynamic typing simply works better when you're dealing with external-interfaces that are dynamic in nature (i.e. data-structures and interfaces defined outside of your software). Web applications, because they deal with a lot of text-manipulation and because they also deal with external data-sources and multiple layers, are the prime example for which dynamic typing works best.
Why do you say that optional static typing
introduced into dynamic languages is a divergence?
Is not a divergence per-se, but the purpose of static types is to prove correctness of types from compile-time. Dynamic languages (as they are used) only need static types for performance reasons, that's why the optimal implementation will consider these types as hints and nothing else. what part of OOP do you see as incompatible
with typing
A static-typing system, to function properly, must be able to trace the true type of a variable throughout the code and be able to use that type at any given time in the compilation process.In OOP you don't know the type of variables at any given time, you can only know its interface at most. And even that is incompatible with OOP, as OOP was also designed around the idea of overriding the method-dispatching being done (even in Java/Scala, all method-dispatching is done at runtime, as you're dispatching based on the implicit parameter).
For example, Scala cannot implement the Hindley–Milner algorithm for type-inference, being forever forced to the current poor implementation that only deals with inferring the type of local variables. And F# / Ocaml on the other hand really have 2 type-systems in a single language (to be able to keep Hidley-Milner , with rules for interoperability. And when working with one or the other, it's like working with different languages.
And the truth of the matter is, if you're watching closely, hybrid languages that are trying to combine static and dynamic really give you the worst of both worlds.
Uh ... invokestatic?
> For example, Scala cannot implement the Hindley–Milner algorithm for type-inference, being forever forced to the current poor implementation that only deals with inferring the type of local variables.
The reason is that Scala has a much more powerful type system, than one that can be inferenced completely by HM (The HM type system was kept simple for exactly that reason).
Actually, the Scala language specification leaves out type inference for a reason: It is improved with every release to inference more and more useful things.
I'm getting slowly annoyed by those people thinking that a HM type system is "the best thing ever". Yes, it is simple, and simple is good.
But look at what Scala's type system can do as a comparison.
Please, get some idea what you are talking about before trolling about it.
I don't think that runtime overwritting and creating of classes is something good per se. It's just better than code generation tools in Java. Well, monkey patching is even worse.
Why is this even needed? What is missing in the programming language to be able to describe these things without the need of dynamic code generation?
Well, monkey patching is even worse.
That's why in my initial comment I talked about style.If you haven't worked with a given style, you're prone to harsh judgments and mentalities such as this one. Redefining classes/methods/interfaces at runtime works great for a lot of people ;)
Why is this even needed?
In case you're working in Java, you may not realize it, but the libraries you're using are probably doing it.The real difference is in these cases, say for example aspect-oriented programming or dependency injection or all the other buzzwords you had to learn for Java in the last 10 years -- which require big-ass, bloated, incomplete and extremely buggy libraries -- in Ruby/Python are as natural as "Hello World!".
To put it simpler - dynamic languages allow you to treat code as data and to mutate it in however ways you like.
Catching bugs at compile-times is not just about syntax-related errors or checking if some object responds to some method call. If you really want to catch errors at compile-time, you have to dig a whole lot deeper than that, which more evolved static languages are kind of doing (mostly by forcing you to model your data-structures in a certain way, such that the language can understand its purpose and mathematically prove stuff).
But then again, Java is not a representative of static-languages, mostly because Java is a fucked-up hybrid, having all the disadvantages of static-types with none of the advantages.
When talking about static types, you really should be talking about what Haskell can do. And even Haskell has limits that dynamic languages don't, that's why it comes with its own macro-language to alleviate that.
I know C++, Python, Common Lisp and Haskell pretty good.
I asked serious questions why problems are solved in the way they're solved, which language features are missing to solve it in another way.
The current way might work for you, but considering bigger projects and human fallibility, I don't think it will scale that well.
Restrictions aren't per se something bad. Considering your own limitations, they can empower you to handle even harder and more complex problems.
I wonder how things like concurrency are expected to work, if no single line of code can be sure that things it expects will exist at runtime. Or maybe exists every 5 seconds for 3 seconds. It is an optimization nightmare (proven by the abhorrent performance Ruby exhibits).
Even the Ruby "developers" have understood that monkey-patching is bad and decided to do something against it.
I estimate fewer than 5% of programmers I've worked with truly understood type theory deeply enough to program a complex system with them properly. In addition, 0% of the systems I've worked on required such strong typing to achieve success.
Typing in Java is comparatively weak, which I view as a feature because it allows you to make more practical trades between expressiveness and simplicity.
Can anybody explain?
# Less coupled
class A:
def foo(self):
print "A"
class B:
def foo(self):
print "B"
for x in (A(), B()):
x.foo()
vs: # More coupled
class Base:
def foo(self):
pass
class A(Base):
def foo(self):
print "A"
class B(Base):
def foo(self):
print "B"
for x in (A(), B()):
x.foo()I'm thinking something like SML. Any others?
A hello world sample: http://hopl.murdoch.edu.au/showexample.prx?exp=59
I want a well-designed statically-typed language, designed that way from the ground up, with a well-thought-out type system, and no insecurities about appealing to C/Java "braces or death!" types
So far my list includes: Eiffel, Haskell, and ML.
Note, I have nothing against dynamic languages - I'm a Rails programmer.
(Seriously, though, what does this have over Scala?)
Just a nitpick, though.
But that's only because the JVM was optimized for Java. And the fastest language around, X86 (or MIPS) assembly, is completely dynamic and loose.
I don't think it's a secret that commercial Smalltalk VMs kicked ass while executing one of the most dynamic languages in existence ... where performance was (and still is) comparable (even better in some tests) to the JVM or .NET
However, most people don't do TDD. With a dynamic language, your compiler isn't doing entire categories of checks for you. You're putting more responsibility on the tests, so you wind up writing more of them sooner and running them almost as frequently as static language users run their compilers!
Since people generally stop long before 100% coverage, you wind up with far more tests for the average dynamic project than the average static one.
Testing is about reducing bugs to a certain level. Entirely different techniques - namely formal proofs - are required to eliminate bugs. Strong static typing is more effective than tests, in terms of cost/benefit, at reducing bugs.
For example, suppose that you are compiling an AST. You start with an AST whose leaves are of type String (identifiers). You want to slot in something else, like pointers to a link table, or values, etc. Maybe some identifiers are builtins which will modify the AST, or user-defined macros, so the transformation will be non-trivial.
In a static language, this transformation would be typed as `AST Identifier -> AST Value`, or the like. This guarantees that you haven't missed any identifiers.
The guarantees provided by static typing tend to be somewhat orthogonal to the guarantees provided by testing. Testing ensures that, in some particular cases, the function works exactly as it should. Types ensure that, in every case, the function satisfies some properties that it should. The ideal would be every case and every property, but this is only possible with complete proofs.
In my experience, types catch more bugs with less effort than tests.
If you are looking for code examples, you can explore here:
https://github.com/languages/Scala
I have been using Scala lately for some personal stuff and I've really fallen in love with it.
[1] - http://www.scala-lang.org/node/5130 [2] - http://www.artima.com/scalazine/articles/twitter_on_scala.ht... [3] - http://www.scala-lang.org/node/6436 [4] - http://www.scala-lang.org/node/7808
BankSimple is building on Scala: https://banksimple.com/
Nasa uses Scala in production: http://www.scala-lang.org/node/6605
Disclaimer: I work at Remember The Milk and I think Scala is a great fit for the problems we're solving.
The companies behind have been merged to a new company called Typesafe which offers Training, consulting, support and a tool stack containing Scala, Akka, Eclipse and SBT.
The persons behind it read like a who-is-who of the JVM world: http://typesafe.com/company/team