Ruby is a dynamic language. Among other things, this means that the types of variables are not predeclared and a single variable may have many different types during the lifetime of a program. This contrasts with languages such as C and Pascal in which the type of each variable is specifically declared and an attempt to assign any other type to that variable is an error.
Dynamic and Static Typing
While dynamic typing is useful for some programming tasks, it has the unfortunate side-effect of making it extremely difficult to provide accurate IntelliSense. Consider the problem: in C or Pascal, before you can use a variable x, you have to state its type – say an Array, an Integer or a String. Once the type has been declared, the IntelliSense system knows that whenever the variable x is encountered within a specific scope, it can treat it with certainty as a variable of the defined type. So if x is a String and the programmer enters x followed by a dot then the code-completion list will always display String methods.
Similarly the return type of functions are specifically declared in statically typed languages – so if function someFunction() is declared to be an Integer, the IntelliSense system knows that it can always assume that the value returned by that function is an Integer.
With Ruby, so such assumptions can be made! Neither the variable x, nor the method, someMethod(), have predeclared types. It is quite possible for x to be an Array, a String and an Integer at various points, and within the same scope, during the execution of a program. The method someMethod() could, equally, have varying return types depending on how that method is called. In many cases, this makes it impossible (even in principle) for the IntelliSense system to work out exactly which type a variable is or which type a method returns – because the method and the variable vary their types at different times during the same program when it runs!
Inference By Scope and Context
The Ruby In Steel IntelliSense system deals with this problem in two ways. In some cases, it is possible to infer the type of a variable at a given point in the code. For example, if a String such as “Hello world” is assigned to x, or the method someMethod() explicitly returns an integer then Ruby In Steel will treat x as a string and someMethod() as an integer. If x is subsequently assigned some other type – say an Array – then Ruby In Steel will henceforward treat it as an array. These are relatively simple examples of 'intelligent inference'.
In fact, Ruby In Steel's intelligent inference engine not only infers the type of a variable within a given scope; it also infers its type within a given context – that is, it attempts to determine which type a variable will have at a certain point when the program is run. This is not foolproof, of course; Ruby In Steel analyses the code while it is still being written and the actual types of variables may not be certain until the program is run by the Ruby interpreter. Nevertheless, allowing for these constraints, Ruby In Steel constantly analyses your code in the background and attempts to determine the most likely types of each variable. So, for example, if x is a string on line 1, an Array on line 100 and an Integer on line 500, when you move to those lines to edit your code, Ruby In Steel attempts to provide the appropriate completion lists for the class of x at that given point in the code. The IntelliSense system calculates completion lists based on a variety of factors such as inheritance, visibility (public, private, class or instance), modularity and inclusion (mixed in modules).
There is no way, however, in which the parameters of a method can be reliably inferred. If you wish to have better Parameter Info IntelliSense for methods, you should consider using Ruby In Steel's Type Assertions.