Optional typing and dynamic languages
After listening to Brendan talk about typing on the latest Open Web Podcast episode on ECMAScript Harmony it got me thinking again about optional typing.
It has always bugged me a little to think of type information in my nice clean dynamic languages (Ruby, JavaScript, Python, Perl, etc.).
Looking at even the simplest of code like this (taken from Mike Chamber’s XMPP server in ActionScript 3)
var room:Room = new Room(connection);
It irks me. Just work out that it is a room already won’t you? I know you can do it? You CAN do it. So, leave it out in this case.
Although the type information is optional, it seems that a lot of the code that I have seen in AS3 puts types in all over the place. I somewhat like the idea of using types when you really need them, such as for clear documentation of a core library, or some performance issue that you find is an issue (note: that becomes an issue, not one that is assumed!)
Once you open the door though, can people play that way? Is giving the programmer a bit switch of “shall I put the type in here?” every few seconds a good thing? Especially when the tools try to put the type in all the time?
I also found it very interesting when Brendan talked about how adding type information can actually hurt performance, sharing an example of when var foo:int
doesn’t do what you actually need. For me, performance is pretty much out of the window, now, and definitely in the future.
So, I lean towards not needing it. But then I flip over the cards and see stuff like this (note: a mock example):
/** * @type Room */ var room = new Room(connection);
Ugh. Now we have the worst of all words. We are documenting the code out of band. This is often done for some jsdoc-like tool that will generate docs for you. The problems are:
- The language itself has no idea about this information. The compiler. Nor, runtime. If there was something that could be done for performance, it couldn’t be
- How easy would it be to get this out of date. If you change the type no one is going to complain. There is no validation here.
- Way more verbose!
This alone makes me think that I would rather have optional types just to avoid any hacks like this.
You?
August 15th, 2008 at 10:17 am
Just to be clear, you do have optional typing in AS3.
Also, another advantage of typing is that you can catch an entire class of programming errors at compile time.
Having worked extensively in JavaScript / ActionScript 1 and then ActionScript 3, I have to say that it is painful on this aspect to move back to JavaScript (although in general I enjoy working with JavaScript).
mike chambers
[email protected]
August 15th, 2008 at 10:28 am
There is definitely plenty of AS3 code out there that doesn’t use types, trust me, I have seen it. The reason you may not have seen it is because it is being produced by companies and organizations that don’t share their product code. In general, the OS AS code that is in the wild is built by programmers who generally have more of a formal background in languages like Java, C#, etc. and so they tend to use the typing features of the language.
Also, in Tamarin typing does indeed increase the performance, despite the comment by Brendan above. The ‘int’ case is a special case which the Tamarin engineers can delve more deeply in than I want to go right now. The new tracing JIT which is being worked on should solve this issue somewhat though, in the sense that untyped code should be more comparable performance wise to typed code.
August 15th, 2008 at 10:54 am
mike,
Yes, I know there is optional typing, which is why I am curious about it :)
Catching errors at compile time is much earlier in the process, and is better. I see value there. I *personally* don’t like verbosity and seem to always enjoy coding in a type-less world (which I can do with AS3… until I touch other peoples code). I am happy with other people writing typed code that I can use untyped too, that is great. I have enjoyed that with JRuby -> Java in the past for example.
August 15th, 2008 at 10:55 am
nit: s/AC3/AS3
(Also, your spam q is “What are the first four letters in the world British” which I naturally thought meant the English-speaking world, and I put in “abcd”. I assume now that “world” should be “word”.)
August 15th, 2008 at 10:56 am
Danny,
Ah, interesting to hear. I am very under-qualified when it comes to seeing a lot of AS3 code, so it is nice to learn from you there.
Tamarin can increase performance now, but I would bet money that:
a) The speed difference may not matter in your app
b) If it does, then speed it up
c) It will matter less and less in the future.
These are all guesses from me and could turn out to be 100% wrong ;)
August 15th, 2008 at 11:03 am
Bill,
Fixed both :) Thanks!
August 15th, 2008 at 11:05 am
>The speed difference may not matter in your app
It matters a lot when you start to talk about more expressive applications and experiences (including 3d). Just ask the papervision 3d guys:
http://blog.papervision3d.org/category/demos/
>It will matter less and less in the future.
My experience working in the Flash community over the years is that to more processing power there is, the more developers and designers will push the boundry of what has been possible. Again, papervision 3d is a good example. It is a complete 3d engine implimented entirely in ActionScript, as is some of the image processing stuff (PNG, JPG encoding) made possible due to performance improvements in AS3.
But yes, for run of the mill apps, with buttons and forms, there is only so much processing power you need. Although, even in that case, more processing power and performance means that you can deal with much larger data sets, and do more advanced data manipulations.
mike chambers
[email protected]
August 15th, 2008 at 11:32 am
Dion, you are confusing lack of type inferencing with type declarations. It’s perfectly possible to have function type parameters, but not have to declare any types on local variables. As often the case in discussions of typing, opponents often cite boilerplate laden languages like Java, but ignore how types work in ML/Haskell/Scala/etc. Just because some people are overzealous with respect to type annotations should not be a strike against the feature. Every feature can be misused.
On the performance side of typing, the conclusion does not follow from the evidence. That is, the fact that adding an int type annotation caused a performance regression in Adobe’s VM implementation, does not mean that type information always leads to poorer performance vs a trace-jit, nor does it mean that the regressions would happen on every VM implementation that leverages type information. There is no a priori reason why a tracing-jit could not also leverage type information as well.
Optimizers are often brittle, and some perturbations cause large regressions. We see this in every language, and you will see it in Tracing JavaScript VMs, that certain constructs will thwart optimizations, which will lead to lots of guides like “How to write optimal Javascript for Tracing JITs”
There are many reasons why types help:
1) performance. Java Hotspot has some characteristics of a trace JIT, more in the vein of the original Self implementation, collecting type feedback and profile information to yield speculative optimizations with guards. It would be instructive to compare JS trace-jits not just against Tamarin, but against Silverlight CLR and JavaFX. Tracing JITs are being oversold. It’s true they are a massive improvement, but they are not going to be winning any language performance shootouts against statically compiled languages. HotSpot was oversold (as was Self) when originally released. Proponents were citing scenarios where it would beat C, but the reality is, it still doesn’t.
2) IDE toolchain. Navigating large code bases and doing safe refactorings are just alot easier to do with types. Types don’t make sense if you’ve only got 100 lines of code, but if you’re “programming in the large” with libraries containing hundreds or thousands of functions, it makes alot of sense. The lack of a standard package/module/namespace system in JS is a crime.
3) Self documenting. The types provide the ability to automatically generate mostly useful documentation, as well as allow programmers to quickly check expectations.
4) “on the wire size”. Trace JITs can help performance, but the optimizations can only be applied *after* the application has been downloaded. With people delivering JS code bases in upwards of 500k, the lack of a package/module system with early binding makes it hard to design preprocessors that strip unused code from the script. GWT, for example, shows how awesome this can become, reducing code size by a factor of 100 in some cases. The result is that everyone roles their own module/build system for concatenating scripts, and inter-library reuse and packaging is reduced.
I personally find that I can deal with missing types for small code bases, but when you get to something like a Google Spreadsheets or GMail app, the lack of types really starts to inhibit productivity. And I would assume that Google agrees, otherwise they would have never built their Javascript compiler, and you would not see /*type*/ stuff showing up in their idiomatic Javascript libraries.
When you see people putting semantically functional data in code comments, it tends to indicate a flaw in the language.
August 18th, 2008 at 2:52 am
I wish the IDEs had a toggle that let me see the types or not.
August 18th, 2008 at 10:01 am
I like dynamic typing all the way. Esp for the web. Let me ask it if it quacks like a duck. Dynamic languages are meritocracies — we only care about what they *do*, not where they’re from. If you have sufficient tests in your app, it’s safe to refactor. Thinking the compiler is a panacea prevents you from writing more tests. Write more tests, and smell them often!
August 18th, 2008 at 1:59 pm
The common response to the refactoring question is “write more tests”, but the Javascript community doesn’t seem to be listening, as most Javascript applications I encounter seem to have little to no tests with obvious exceptions to big popular community projects (like Dojo). And the code coverage compares poorly with Java. This seems to be the case even though unit tests are easier to write in Javascript then in Java and more important to have in Javascript!
I like Nosredna’s suggesting. Allow the IDE a “hidden types” mode where you don’t see the declarations. Come to think of it, they could do this for Java as well in many cases. I proposed something similar in the Java Closures debate, which is implement a Java IDE extension which shows BGGA Closures as Anonymous Inner Classes for those who prefer more verbosity.
I think choice is best. I’m surprised that many people want to take away choice from others based on their own personal aesthetic preferences.
August 18th, 2008 at 3:12 pm
I have always liked the idea of giving the IDE power to hide things and such. We already have that with hiding blocks / comments etc.
I would like to see this taken further and have my view on top of the data, which can be tweaked. E.g. I can set my brace style and even if it is different from the code, I see it how I like it. This fits into the same problem.
August 18th, 2008 at 3:35 pm
Ray, even with a compiler, you still have to write the tests. Irresponsible developers will have a compiler, and will still be missing tests. I don’t think that necessarily moves you forward. My two cents.
…try Screw-Unit for JavaScript BDD… if you like RSpec for Ruby, you’ll like it:
http://github.com/nkallen/screw-unit/tree/master
http://github.com/nkallen/screw-unit/tree/master/README.markdown
August 19th, 2008 at 6:08 am
Optional type systems really seem to add a bunch of complexity for little gain. I feel languages really need to pick one way and go for it. If the language has dynamic goodness then forget the types, if it is statically typed hope for some good inferencing a la haskell.
The language that really gets me is groovy. Not only does it have optional types. If you use them, the code is slower and they do not get checked up front so you can still assign ‘Bar b = new Foo()’ even if they are totally incompatible, it will then fail at runtime at the same place it would have without the type.
August 19th, 2008 at 10:17 am
I’m not sure how often you other JavaScript programmers jump around through the new IDEs, but I noticed that a couple I tried recently (I think Komodo and NetBeans) do an amazing job of keeping track of the types in JavaScript. They must almost be running your code! It’s very impressive. Even though you aren’t telling them the types, they are looking at your code to figure out the types, and are as strict in warning you as Flex 3 is with AS3.
To extend my previous wish, I think AS3 and JS could almost be merged in the IDEs. A “show types” option could work in either AS3 (optional hiding) or JS (optional showing).
August 20th, 2008 at 2:13 am
Nosredna, I believe most of these IDEs are using a combination of three techniques: 1) intrinsic DB of most browser methods (e.g. document.*), this is how IntelliJ IDEA does it, you can even edit the database. 2) detection of idiomatic Javascript patterns, e.g. foo.bar.Baz.prototype.method = expression = “early binding” static function definition, the IDE will detect this and treat it as an early-bound method on Baz. 3) Limited type-flow, that is if var a = new Baz(), and you invoke foo(a), and foo invokes bar(a), then bar()’s argument will be assumed to be of type Baz. It doesn’t need to run the code to do this, it can just build a CFG of the code.
I’ve yet to see a JS IDE work like Smalltalk/Forth/Factor/etc in the sense that you edit with respect to the current memory image of the interpreter.
Hibberd, static languages with optional types differ somewhat from dynamic languages with optional types. With static languages that include type inferencing, like those based on ML, you omit type declarations, but you do not forfeit strong typing nor performance. Methods without types merely become parametric.
For example,
add(x, y) = x + y
If called as add(1,2) it compiles as add(int,int), if called with add(1.2, 2.3) it compiles as add(double,double), and if called with add(1.2, “Foo”) it throws a compile error because in this case, the intrinsic “+” operator doesn’t support (int,String) are parameters.