Ruby Variable Completion – The Challenges of Code Analysis
One of the beta testers of the Developer Edition of Ruby In Steel (‘Red Fire’) suggested recently that we should think of doing automatic variable completion: that is, if you have three variables in scope called, say, dogOne, dogTwo and dogmaticTheoriesAndPrinciples you should be able to type a letter or two – say do - and pick the appropriate variable from a drop-down list.
I have to be honest. The plain truth of the matter is that we’ve added so many IntelliSense features to the latest version that I couldn’t at first recall whether or not we’d done this. With a sigh of relief, when I came to try it out, I found that we had. Anyway, this latest version went off to our beta test group yesterday, so that they can all try to break it, the little devils…
- Yup! We do have variable auto-completion lists. Phew! That’s a relief...
The Challenge of IntelliSense
IntelliSense has been one of the biggest challenges in the entire development process of Ruby In Steel. On the one hand, Visual Studio provides a lot of the ‘support tools’ to make IntelliSense possible. By that I mean that the software inherently ‘knows about’ things such as dropdown completion lists and hovering tooltips, so we haven’t had to code all that stuff from scratch. That’s one of the main reasons why we decided to create Ruby In Steel for Visual Studio in the first place. If we’d had to write all the fundamental editing, debugging, project management and support features, we couldn’t possibly have made progress anything like as rapidly as we have.
On the other hand, IntelliSense for Ruby doesn’t “just happen”. Far from it! We’ve had to write a big and complex parser which is now, in fact, not far short of a dedicated Ruby interpreter in its on right. In order to get IntelliSense right – that is, a system which produces completion lists that show the correct methods and variables according to the scope and type of any given object – our software is constantly analysing code as it is typed. That’s a hard problem to deal with even in a statically typed language . With a language as dynamic as Ruby – one that not only doesn’t have type declarations but also allows you to write code that works with various types of object, only determined at runtime – this problem becomes phenomenally difficult: indeed, in many circumstances, there is no ‘correct’ solution to the problem.
Solving The Impossible?
Let me explain this. In essence our parser has to try to make sense of a Ruby program before it is even finished. We can’t succeed 100% in this; we can try – but the problem is inherently insoluble. There are times when it simply isn’t possible to guess what a certain variable may be at some arbitrary point in a yet-to-be-completed program. This is a particular problem with arguments to methods. The arguments are untyped and one method may, in principle, be capable of taking varying types of arguments; so it would be incorrect to ‘infer’, at design-time, the type of any given argument.
Nevertheless, there are times when the programmer intends that certain methods should always take certain types of argument and it would be darn’ useful to know what these arguments are when you are calling that method. That’s why we’ve introduced ‘argument assertions’. These are comment blocks in which you can state the types of arguments you expect and also the type of argument the method should return. These comments are then used to display this information in parameter tooltips when you call the method. Dermot wrote more about this HERE.
All these features have been put into beta 0.9 which we’ve just sent to our testers. For the next beta release we are concentrating on Rails development features. Rails poses different problems to normal Ruby (its Ruby files don’t even specify the files they ‘require’, which makes it extraordinarily difficult to provide ‘on the fly’ code analysis). I’ll explain more about the new Rails features after our next beta release.