views:

241

answers:

4

Hi all!

I am looking for various approaches for supporting some level of intellisense on a dynamically typed language. Since intellisense information is based on type information, there are inherent difficulties in implementing this for dynamic languages.

Do you know any algorithms or methods to implemented it?

A: 

Easy, just one additional step should be added - type inference. After that you know type information and can suggest something to the user.

vava
Actually, I am asking about how to do type inferene for dynamically typed language.
A: 

Note that a "dynamic language" and a "dynamically typed language" are not necessarily the same thing.

The way that Microsoft handles this in the intellisense for Javascript (VS2008) is that it infers, to the best of its ability, what type the var currently holds. If/when this changes, following references to the var will present options for the updated type.

GalacticCowboy
+1  A: 

I would download the sources of the Groovy plugin for eclipse, it has intellisense (as much as possible), and think Groovy is a good sample of a dyanamic language with dynamic typing

Ehrann Mehdan
+6  A: 

You need to write an abstract interpreter that executes the code with type values. So you step with your abstract interpreter trough the AST and record for each variable the sent messages or known types. And when you are done, you infer the possible types using structural type equivalence (aka duck typing).

PS: in addition to type inference you might want to take a look at "How Program History Can Improve Code Completion" by Romain Robbes, is explains how to further improve auto completion in dynamic languages with most-recently-used information and collaborative filtering.

So here is how abstract interpretation works for a code snippet like

def groups(array,&block)
  groups = Hash.new
  array.each { |ea| 
    key = block.call(ea)
    groups[key] = [] unless groups.include? key
    groups[key] << ea
  }
  return groups
end

you would start with

array = { :messages => [], :types => [] }
block = { :messages => [], :types => [] }

and then

array = { :messages => [], :types => [] }
block = { :messages => [], :types => [] }
groups = { :messages => [], :types => [Hash] }

and then

array = { :messages => [:each], :types => [] }
block = { :messages => [], :types => [] }
groups = { :messages => [], :types => [Hash] }

and then

array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [], :types => [Hash] }
key = {  :messages => [], :types => [] }

and then

array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [:include?,:[]], :types => [Hash] }
group_elements = { :messages => [], :types => [Array] }
key = { :messages => [], :types => [] }

and then

array = { :messages => [:each], :types => [] }
block = { :messages => [:call], :types => [] }
groups = { :messages => [:include?,:[]], :types => [Hash] }
group_elements = { :messages => [:<<], :types => [Array] }
key = { :messages => [], :types => [] }

so eventually we can infer that

  • array is possibly an Enumerable
  • block is possibly a Proc
  • groups is a Hash with Array elements
  • key is any object
Adrian

related questions