This excellent post on Tern’s internals reminded me of why I lost interest of my statically typed Lua project.
I lost my interest in a program exponentially with the amount of hacky solutions it involves.
I love Lua, it’s so simple but it is so powerful at the same time, without having any quirks most other dynamic languages have. But when it comes developing a type inference system for such a dynamic language, the result will have to contain a lot of hacks.
Here’s a quote from Tern post, which explains handling dynamically extending objects:
And now we’re off into dodgy hack land. In order to meet this challenge, Tern uses a special treatment for for/in loops that appear to be copying properties. When it encounters them, it assumes that the properties from the source object will be copied to the target object. It ignores control flow (conditionals and such) and simply copies all properties.
Similar situation is applied to Lua and this is where I dropped my project. Basically, there is no way to give a type to an object without actually running the program to the point where completion is needed. But even then you can’t have completely correct type information because for instance, you may have a different object in second iteration of loop but your type inference system would be only run it for one iteration. Still, I think running a program in an isolated environment to the point where enough type information is acquired is the best way to infer types in dynamic languages.
Accepting having a subset of Lua and forbidding object extensions in run-time is not a solution because then you can’t even use tables as, well, tables, rather than objects.
The obvious solution is creating a new syntax for defining objects. That syntax should be allowed only in top-level of a file, ie. you can’t use object definition syntax inside of a function.
But then a new language that is not Lua would be invented. I deliberately wanted to avoid this situation because in my opinion, it’s slightly missing the point of that kind of languages. I don’t like CoffeeScript’s additional compile step to my workflow. One nice property of dynamic languages is that we don’t have any visible intermediate steps between writing the source code and running it. All intermediate steps(parsing, compiling to some kind of byte-code, like Python does) are completely hidden to programmer.
Maybe the problem is that I’m looking for a perfect solution which does not exist in reality. I’m not sure how can I overcome this problem, I don’t want to work on programs full of hacks in my free time(well, I don’t want to work on this kind of programs in any time, but doing that as a hobby is more unbearable).